﻿using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Runtime.ConstrainedExecution;
using System.Text;
using ActiveDirectoryUtilities.CommonLibrary.Unsafe;

//using RPC_AUTH_IDENTITY_HANDLE = ActiveDirectoryUtilities.CommonLibrary.Unsafe.RpcDce.RPC_AUTH_IDENTITY_HANDLE;
using RPC_AUTH_IDENTITY_HANDLE = System.IntPtr;
using DWORD = System.UInt32;
using HANDLE = System.IntPtr;
using ULONG = System.UInt32;
using USHORT = System.UInt16;
using UUID = System.Guid;
using USN = System.Int64;

namespace ActiveDirectoryUtilities.CommonLibrary.Unsafe
{
	static public class NtDsApi
	{
		[SuppressUnmanagedCodeSecurity, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
		public class DsHandle : SafeHandle
		{
			public DsHandle()
				: base(IntPtr.Zero, true)
			{
			}

			public override bool IsInvalid
			{
				get { return this.IsClosed || handle == IntPtr.Zero; }
			}

			[SuppressUnmanagedCodeSecurity, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
			protected override bool ReleaseHandle()
			{
				DWORD ret = NtDsApi.DsUnBind(handle);
				System.Diagnostics.Debug.WriteLineIf(ret != 0, "Error unbinding :\t" + ret.ToString());
				return ret == 0;
			}
		}

		[SuppressUnmanagedCodeSecurity, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
		public class RPC_AUTH_IDENTITY_HANDLE : SafeHandle
		{
			public RPC_AUTH_IDENTITY_HANDLE()
				: base(IntPtr.Zero, true)
			{
			}

			public override bool IsInvalid
			{
				get { return this.IsClosed || handle == IntPtr.Zero; }
			}

			protected override bool ReleaseHandle()
			{
				NtDsApi.DsFreePasswordCredentials(this);
				return true;
			}
		}

		#region Data definitions
		// Following constants define the Active Directory Behavior Version numbers.
		public const uint DS_BEHAVIOR_WIN2000 = 0;
		public const uint DS_BEHAVIOR_WIN2003_WITH_MIXED_DOMAINS = 1;
		public const uint DS_BEHAVIOR_WIN2003 = 2;
		public const uint DS_BEHAVIOR_WIN2008 = 3;
		public const uint DS_BEHAVIOR_WIN2008R2 = 4;

		//Deprecated constants
		public const uint DS_BEHAVIOR_LONGHORN = DS_BEHAVIOR_WIN2008;
		public const uint DS_BEHAVIOR_WIN7 = DS_BEHAVIOR_WIN2008R2;

		/// <summary>
		/// When booted to DS mode, this event is signalled when the DS has completed
		/// its initial sync attempts.  The period of time between system startup and
		/// this event's state being set is indeterminate from the local service's
		/// standpoint.  In the meantime the contents of the DS should be considered
		/// incomplete / out-dated, and the machine will not be advertised as a domain
		/// controller to off-machine clients.  Other local services that rely on
		/// information published in the DS should avoid accessing (or at least
		/// relying on) the contents of the DS until this event is set.
		/// </summary>
		public const string DS_SYNCED_EVENT_NAME = "NTDSInitialSyncsCompleted";

		// Permissions bits used in security descriptors in the directory.
		public const uint ACTRL_DS_OPEN = 0x00000000;
		public const uint ACTRL_DS_CREATE_CHILD = 0x00000001;
		public const uint ACTRL_DS_DELETE_CHILD = 0x00000002;
		public const uint ACTRL_DS_LIST = 0x00000004;
		public const uint ACTRL_DS_SELF = 0x00000008;
		public const uint ACTRL_DS_READ_PROP = 0x00000010;
		public const uint ACTRL_DS_WRITE_PROP = 0x00000020;
		public const uint ACTRL_DS_DELETE_TREE = 0x00000040;
		public const uint ACTRL_DS_LIST_OBJECT = 0x00000080;
		public const uint ACTRL_DS_CONTROL_ACCESS = 0x00000100;

		/// <summary>
		/// generic read
		/// </summary>
		public const uint DS_GENERIC_READ = ((Winnt.STANDARD_RIGHTS_READ) | (ACTRL_DS_LIST) | (ACTRL_DS_READ_PROP) | (ACTRL_DS_LIST_OBJECT));

		/// <summary>
		/// generic execute
		/// </summary>
		public const uint DS_GENERIC_EXECUTE = ((Winnt.STANDARD_RIGHTS_EXECUTE) | (ACTRL_DS_LIST));


		/// <summary>
		///  generic write
		/// </summary>
		public const uint DS_GENERIC_WRITE = ((Winnt.STANDARD_RIGHTS_WRITE) | (ACTRL_DS_SELF) | (ACTRL_DS_WRITE_PROP));

		/// <summary>
		/// generic all
		/// </summary>
		public const uint DS_GENERIC_ALL = ((Winnt.STANDARD_RIGHTS_REQUIRED) | (ACTRL_DS_CREATE_CHILD) | (ACTRL_DS_DELETE_CHILD) | (ACTRL_DS_DELETE_TREE) | (ACTRL_DS_READ_PROP) | (ACTRL_DS_WRITE_PROP) | (ACTRL_DS_LIST) | (ACTRL_DS_LIST_OBJECT) | (ACTRL_DS_CONTROL_ACCESS) | (ACTRL_DS_SELF));

		/// <summary>
		/// The DS_NAME_FORMAT enumeration provides formats to use for input and output names for the DsCrackNames function.
		/// </summary>
		public enum DS_NAME_FORMAT : uint
		{
			/// <summary>
			/// unknown name type
			/// </summary>
			DS_UNKNOWN_NAME = 0,

			/// <summary>
			/// eg: CN=User Name,OU=Users,DC=Example,DC=Microsoft,DC=Com
			/// </summary>
			DS_FQDN_1779_NAME = 1,

			/// <summary>
			/// eg: Example\UserN
			/// Domain-only version includes trailing '\\'.
			/// </summary>
			DS_NT4_ACCOUNT_NAME = 2,

			/// <summary>
			/// Probably "User Name" but could be something else.  I.e. The
			/// display name is not necessarily the defining RDN.
			/// </summary>
			DS_DISPLAY_NAME = 3,

			// obsolete - see #define later
			// DS_DOMAIN_SIMPLE_NAME = 4,

			// obsolete - see #define later
			// DS_ENTERPRISE_SIMPLE_NAME = 5,

			/// <summary>
			/// String-ized GUID as returned by IIDFromString().
			/// eg: {4fa050f0-f561-11cf-bdd9-00aa003a77b6}
			/// </summary>
			DS_UNIQUE_ID_NAME = 6,

			/// <summary>
			/// eg: example.microsoft.com/software/user name
			/// Domain-only version includes trailing '/'.
			/// </summary>
			DS_CANONICAL_NAME = 7,

			/// <summary>
			/// eg: usern@example.microsoft.com
			/// </summary>
			DS_USER_PRINCIPAL_NAME = 8,

			/// <summary>
			/// Same as DS_CANONICAL_NAME except that rightmost '/' is
			/// replaced with '\n' - even in domain-only case.
			/// eg: example.microsoft.com/software\nuser name
			/// </summary>
			DS_CANONICAL_NAME_EX = 9,

			/// <summary>
			/// eg: www/www.microsoft.com@example.com - generalized service principal
			/// names.
			/// </summary>
			DS_SERVICE_PRINCIPAL_NAME = 10,

			/// <summary>
			/// This is the string representation of a SID.  Invalid for formatDesired.
			/// See sddl.h for SID binary <--> text conversion routines.
			/// eg: S-1-5-21-397955417-626881126-188441444-501
			/// </summary>
			DS_SID_OR_SID_HISTORY_NAME = 11,

			/// <summary>
			/// Pseudo-name format so GetUserNameEx can return the DNS domain name to
			/// a caller.  This level is not supported by the DS APIs.
			/// </summary>
			DS_DNS_DOMAIN_NAME = 12
		};

		// Map old name formats to closest new format so that old code builds
		// against new headers w/o errors and still gets (almost) correct result.
		public const uint DS_DOMAIN_SIMPLE_NAME = (uint)DS_NAME_FORMAT.DS_USER_PRINCIPAL_NAME;
		public const uint DS_ENTERPRISE_SIMPLE_NAME = (uint)DS_NAME_FORMAT.DS_USER_PRINCIPAL_NAME;

		/// <summary>
		/// The DS_NAME_FLAGS enumeration is used to define how the name syntax will be cracked. These flags are used by the <see cref="DsCrackNames"/> function
		/// </summary>
		[Flags]
		public enum DS_NAME_FLAGS : uint
		{
			/// <summary>
			/// Indicates that there are no associated flags.
			/// </summary>
			DS_NAME_NO_FLAGS = 0x0,

			/// <summary>
			/// Perform a syntactical mapping at the client (if possible) without
			/// going out on the wire.  Returns <see cref="DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING"/>
			/// if a purely syntactical mapping is not possible.
			/// </summary>
			DS_NAME_FLAG_SYNTACTICAL_ONLY = 0x1,

			/// <summary>
			/// Force a trip to the DC for evaluation, even if this could be
			/// locally cracked syntactically.
			/// </summary>
			DS_NAME_FLAG_EVAL_AT_DC = 0x2,

			/// <summary>
			/// The call fails if the DC is not a GC
			/// </summary>
			DS_NAME_FLAG_GCVERIFY = 0x4,

			/// <summary>
			/// Enable cross forest trust referral
			/// </summary>
			DS_NAME_FLAG_TRUST_REFERRAL = 0x8
		};

		/// <summary>
		/// The DS_NAME_ERROR enumeration defines the errors returned by the status member of the <see cref="DS_NAME_RESULT_ITEM"/> structure. These are potential errors that may be encountered while a name is converted by the <see cref="DsCrackNames"/> function.
		/// </summary>
		public enum DS_NAME_ERROR : uint
		{
			DS_NAME_NO_ERROR = 0,

			/// <summary>
			/// Generic processing error.
			/// </summary>
			DS_NAME_ERROR_RESOLVING = 1,

			/// <summary>
			/// Couldn't find the name at all - or perhaps caller doesn't have
			/// rights to see it.
			/// </summary>
			DS_NAME_ERROR_NOT_FOUND = 2,

			/// <summary>
			/// Input name mapped to more than one output name.
			/// </summary>
			DS_NAME_ERROR_NOT_UNIQUE = 3,

			/// <summary>
			/// Input name found, but not the associated output format.
			/// Can happen if object doesn't have all the required attributes.
			/// </summary>
			DS_NAME_ERROR_NO_MAPPING = 4,

			/// <summary>
			/// Unable to resolve entire name, but was able to determine which
			/// domain object resides in.  Thus DS_NAME_RESULT_ITEM?.pDomain
			/// is valid on return.
			/// </summary>
			DS_NAME_ERROR_DOMAIN_ONLY = 5,

			/// <summary>
			/// Unable to perform a purely syntactical mapping at the client
			/// without going out on the wire.
			/// </summary>
			DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING = 6,

			/// <summary>
			/// The name is from an external trusted forest.
			/// </summary>
			DS_NAME_ERROR_TRUST_REFERRAL = 7
		};

		public const uint DS_NAME_LEGAL_FLAGS = (uint)DS_NAME_FLAGS.DS_NAME_FLAG_SYNTACTICAL_ONLY;

		/// <summary>
		/// The DS_SPN_NAME_TYPE enumeration is used by the DsGetSPN function to identify the format for composing SPNs.
		/// </summary>
		public enum DS_SPN_NAME_TYPE : uint
		{
			/// <summary>
			/// "paulle-nec.ntwksta.ms.com"
			/// </summary>
			DS_SPN_DNS_HOST = 0,

			/// <summary>
			/// "cn=paulle-nec,ou=computers,dc=ntwksta,dc=ms,dc=com"
			/// </summary>
			DS_SPN_DN_HOST = 1,

			/// <summary>
			/// "paulle-nec"
			/// </summary>
			DS_SPN_NB_HOST = 2,

			/// <summary>
			/// "ntdev.ms.com"
			/// </summary>
			DS_SPN_DOMAIN = 3,

			/// <summary>
			/// "ntdev"
			/// </summary>
			DS_SPN_NB_DOMAIN = 4,

			/// <summary>
			/// "cn=anRpcService,cn=RPC Services,cn=system,dc=ms,dc=com"
			/// "cn=aWsService,cn=Winsock Services,cn=system,dc=ms,dc=com"
			/// "cn=aService,dc=itg,dc=ms,dc=com"
			/// "www.ms.com", "ftp.ms.com", "ldap.ms.com"
			/// "products.ms.com"
			/// </summary>
			DS_SPN_SERVICE = 5
		};

		/// <summary>
		/// The DS_SPN_WRITE_OP enumeration identifies the type of write operation that should be performed by the DsWriteAccountSpn function.
		/// </summary>
		public enum DS_SPN_WRITE_OP : uint
		{
			/// <summary>
			/// add SPNs
			/// </summary>
			DS_SPN_ADD_SPN_OP = 0,
			/// <summary>
			/// set all SPNs
			/// </summary>
			DS_SPN_REPLACE_SPN_OP = 1,
			/// <summary>
			/// Delete SPNs
			/// </summary>
			DS_SPN_DELETE_SPN_OP = 2
		};

		/// <summary>
		/// The DS_NAME_RESULT_ITEM structure contains a name converted by the DsCrackNames function, along with associated error and domain data.
		/// </summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_NAME_RESULT_ITEM
		{
			/// <summary>
			/// DS_NAME_ERROR
			/// </summary>
			public DS_NAME_ERROR status;
			/// <summary>
			/// DNS domain
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			public string pDomain;
			/// <summary>
			/// name in requested format
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			public string pName;
		}

		/// <summary>
		/// The DS_NAME_RESULT structure is used with the DsCrackNames function to contain the names converted by the function.
		/// </summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_NAME_RESULT
		{
			/// <summary>
			/// item count
			/// </summary>
			public DWORD cItems;
			/// <summary>
			/// item array
			/// </summary>
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct)]
			public DS_NAME_RESULT_ITEM[] rItems;
		}



		// ********************
		// DsBindWithSpnEx flags
		// ********************
		/// <summary>
		/// Allow the Bind to use delegate service level, so that you can
		/// do ntdsapi operations that require delegation, such as
		/// DsAddSidHistory, and DsReplicaSyncAll().  Most operations do
		/// not require DELEGATE so this flag should only be specified
		/// if you need it, because if you bind to a rogue server with
		/// the DELEGATE flag, you'll allow the rogue server to use your
		/// credentials to connect back to a non-rogue server and perform
		/// </summary>
		public const uint NTDSAPI_BIND_ALLOW_DELEGATION = 0x00000001;
		/// <summary>
		/// With AD/AM, a single machine, could have multiple "AD's" on a
		/// single server.  Since DsBindXxxx() will not pick an AD/AM
		/// instance without an instance specifier ( ":389" ), it can be
		/// difficult (well impossible) to determine from just a server
		/// name, what the instance annotation or instance guid is.  This
		/// option will take a server name and find the first available
		/// AD or AD/AM instance.  WARNING: The results could be non-
		/// deterministic on a server w/ multiple instances.
		/// </summary>
		public const uint NTDSAPI_BIND_FIND_BINDING = 0x00000002;
		/// <summary>
		/// We have a family of API's for binding called DsBindWithSpn.
		/// Would anyone who called these and passed in a non-NULL SPN
		/// ever want to negotiate down to something that doesn't use that
		/// SPN?  No, this is a security hole.  So, for backwards compatibility
		/// if you call without an SPN, we'll create one for you, and attempt
		/// to use it, and allow negotiation to do it's thing if it doesn't
		/// work.
		/// </summary>
		public const uint NTDSAPI_BIND_FORCE_KERBEROS = 0x00000004;



		// ********************
		// Replica Sync flags
		// These flag values are used both as input to DsReplicaSync and
		// as output from DsReplicaGetInfo, PENDING_OPS, DS_REPL_OPW.ulOptions
		// ********************
		/// <summary>
		/// Perform this operation asynchronously.
		/// </summary>
		public const uint DS_REPSYNC_ASYNCHRONOUS_OPERATION = 0x00000001;
		/// <summary>
		/// Writeable replica.  Otherwise, read-only.
		/// </summary>
		public const uint DS_REPSYNC_WRITEABLE = 0x00000002;
		/// <summary>
		/// This is a periodic sync request as scheduled by the admin.
		/// </summary>
		public const uint DS_REPSYNC_PERIODIC = 0x00000004;
		/// <summary>
		/// Use inter-site messaging
		/// </summary>
		public const uint DS_REPSYNC_INTERSITE_MESSAGING = 0x00000008;
		/// <summary>
		/// Sync starting from scratch (i.e., at the first USN).
		/// </summary>
		public const uint DS_REPSYNC_FULL = 0x00000020;
		/// <summary>
		/// This is a notification of an update that was marked urgent.
		/// </summary>
		public const uint DS_REPSYNC_URGENT = 0x00000040;
		/// <summary>
		/// Don't discard this synchronization request, even if a similar
		/// sync is pending.
		/// </summary>
		public const uint DS_REPSYNC_NO_DISCARD = 0x00000080;
		/// <summary>
		/// Sync even if link is currently disabled.
		/// </summary>
		public const uint DS_REPSYNC_FORCE = 0x00000100;
		/// <summary>
		/// Causes the source DSA to check if a reps-to is present for the local DSA
		/// (aka the destination). If not, one is added.  This ensures that
		/// source sends change notifications.
		/// </summary>
		public const uint DS_REPSYNC_ADD_REFERENCE = 0x00000200;
		/// <summary>
		/// A sync from this source has never completed (e.g., a new source).
		/// </summary>
		public const uint DS_REPSYNC_NEVER_COMPLETED = 0x00000400;
		/// <summary>
		/// When this sync is complete, requests a sync in the opposite direction.
		/// </summary>
		public const uint DS_REPSYNC_TWO_WAY = 0x00000800;
		/// <summary>
		/// Do not request change notifications from this source.
		/// </summary>
		public const uint DS_REPSYNC_NEVER_NOTIFY = 0x00001000;
		/// <summary>
		/// Sync the NC from this source when the DSA is started.
		/// </summary>
		public const uint DS_REPSYNC_INITIAL = 0x00002000;
		/// <summary>
		/// Use compression when replicating.  Saves message size (e.g., network
		/// bandwidth) at the expense of extra CPU overhead at both the source and
		/// destination servers.
		/// </summary>
		public const uint DS_REPSYNC_USE_COMPRESSION = 0x00004000;
		/// <summary>
		/// Sync was abandoned for lack of updates (W2K, W2K3)
		/// </summary>
		public const uint DS_REPSYNC_ABANDONED = 0x00008000;
		/// <summary>
		/// Special secret processing
		/// </summary>
		public const uint DS_REPSYNC_SELECT_SECRETS = 0x00008000;
		/// <summary>
		/// Initial sync in progress
		/// </summary>
		public const uint DS_REPSYNC_INITIAL_IN_PROGRESS = 0x00010000;
		/// <summary>
		/// Partial Attribute Set sync in progress
		/// </summary>
		public const uint DS_REPSYNC_PARTIAL_ATTRIBUTE_SET = 0x00020000;
		/// <summary>
		/// Sync is being retried
		/// </summary>
		public const uint DS_REPSYNC_REQUEUE = 0x00040000;
		/// <summary>
		/// Sync is a notification request from a source
		/// </summary>
		public const uint DS_REPSYNC_NOTIFICATION = 0x00080000;
		/// <summary>
		/// Sync is a special form which requests to establish contact
		/// now and do the rest of the sync later
		/// </summary>
		public const uint DS_REPSYNC_ASYNCHRONOUS_REPLICA = 0x00100000;
		/// <summary>
		/// Request critical objects only
		/// </summary>
		public const uint DS_REPSYNC_CRITICAL = 0x00200000;
		/// <summary>
		/// A full synchronization is in progress
		/// </summary>
		public const uint DS_REPSYNC_FULL_IN_PROGRESS = 0x00400000;
		/// <summary>
		/// Synchronization request was previously preempted
		/// </summary>
		public const uint DS_REPSYNC_PREEMPTED = 0x00800000;
		/// <summary>
		/// Non GC readonly replica
		/// </summary>
		public const uint DS_REPSYNC_NONGC_RO_REPLICA = 0x01000000;

		// ********************
		// Replica Add flags
		// ********************

		/// <summary>
		/// Perform this operation asynchronously.
		/// </summary>
		public const uint DS_REPADD_ASYNCHRONOUS_OPERATION = 0x00000001;
		/// <summary>
		/// Create a writeable replica.  Otherwise, read-only.
		/// </summary>
		public const uint DS_REPADD_WRITEABLE = 0x00000002;
		/// <summary>
		/// Sync the NC from this source when the DSA is started.
		/// </summary>
		public const uint DS_REPADD_INITIAL = 0x00000004;
		/// <summary>
		/// Sync the NC from this source periodically, as defined by the
		/// schedule passed in the preptimesSync argument.
		/// </summary>
		public const uint DS_REPADD_PERIODIC = 0x00000008;
		/// <summary>
		/// Sync from the source DSA via an Intersite Messaging Service (ISM) transport
		/// (e.g., SMTP) rather than native DS RPC.
		/// </summary>
		public const uint DS_REPADD_INTERSITE_MESSAGING = 0x00000010;
		/// <summary>
		/// Don't replicate the NC now -- just save enough state such that we
		/// know to replicate it later.
		/// </summary>
		public const uint DS_REPADD_ASYNCHRONOUS_REPLICA = 0x00000020;
		/// <summary>
		/// Disable notification-based synchronization for the NC from this source.
		/// This is expected to be a temporary state; the similar flag
		/// DS_REPADD_NEVER_NOTIFY should be used if the disable is to be more permanent.
		/// </summary>
		public const uint DS_REPADD_DISABLE_NOTIFICATION = 0x00000040;
		/// <summary>
		/// Disable periodic synchronization for the NC from this source
		/// </summary>
		public const uint DS_REPADD_DISABLE_PERIODIC = 0x00000080;
		/// <summary>
		/// Use compression when replicating.  Saves message size (e.g., network
		/// bandwidth) at the expense of extra CPU overhead at both the source and
		/// destination servers.
		/// </summary>
		public const uint DS_REPADD_USE_COMPRESSION = 0x00000100;
		/// <summary>
		/// Do not request change notifications from this source.  When this flag is
		/// set, the source will not notify the destination when changes occur.
		/// Recommended for all intersite replication, which may occur over WAN links.
		/// This is expected to be a more or less permanent state; the similar flag
		/// DS_REPADD_DISABLE_NOTIFICATION should be used if notifications are to be
		/// disabled only temporarily.
		/// </summary>
		public const uint DS_REPADD_NEVER_NOTIFY = 0x00000200;
		/// <summary>
		/// When this sync is complete, requests a sync in the opposite direction.
		/// </summary>
		public const uint DS_REPADD_TWO_WAY = 0x00000400;
		/// <summary>
		/// Request critical objects only
		/// Critical only is only allowed while installing
		/// A critical only sync does not bring all objects in the partition. It
		/// replicates just the ones necessary for minimal directory operation.
		/// A normal, non-critical sync must be performed before the partition
		/// can be considered fully synchronized.
		/// </summary>
		public const uint DS_REPADD_CRITICAL = 0x00000800;
		/// <summary>
		/// Special secret processing
		/// </summary>
		public const uint DS_REPADD_SELECT_SECRETS = 0x00001000;
		/// <summary>
		/// Non GC RO Replica
		/// </summary>
		public const uint DS_REPADD_NONGC_RO_REPLICA = 0x01000000;



		// ********************
		// Replica Delete flags
		// ********************
		/// <summary>
		/// Perform this operation asynchronously.
		/// </summary>
		public const uint DS_REPDEL_ASYNCHRONOUS_OPERATION = 0x00000001;
		/// <summary>
		/// The replica being deleted is writeable.
		/// </summary>
		public const uint DS_REPDEL_WRITEABLE = 0x00000002;
		/// <summary>
		/// Replica is a mail-based replica
		/// </summary>
		public const uint DS_REPDEL_INTERSITE_MESSAGING = 0x00000004;
		/// <summary>
		/// Ignore any error generated by contacting the source to tell it to scratch
		/// this server from its Reps-To for this NC.
		/// </summary>
		public const uint DS_REPDEL_IGNORE_ERRORS = 0x00000008;
		/// <summary>
		/// Do not contact the source telling it to scratch this server from its
		/// Rep-To for this NC.  Otherwise, if the link is RPC-based, the source will
		/// be contacted.
		/// </summary>
		public const uint DS_REPDEL_LOCAL_ONLY = 0x00000010;
		/// <summary>
		/// Delete all the objects in the NC
		/// "No source" is incompatible with (and rejected for) writeable NCs.  This is
		/// valid only for read-only NCs, and then only if the NC has no source.  This
		/// can occur when the NC has been partially deleted (in which case the KCC
		/// periodically calls the delete API with the "no source" flag set).
		/// </summary>
		public const uint DS_REPDEL_NO_SOURCE = 0x00000020;
		/// <summary>
		/// Allow deletion of read-only replica even if it sources
		/// other read-only replicas.
		/// </summary>
		public const uint DS_REPDEL_REF_OK = 0x00000040;


		// ********************
		// Replica Modify flags
		// ********************
		/// <summary>
		/// Perform this operation asynchronously.
		/// </summary>
		public const uint DS_REPMOD_ASYNCHRONOUS_OPERATION = 0x00000001;
		/// <summary>
		/// The replica is writeable.
		/// </summary>
		public const uint DS_REPMOD_WRITEABLE = 0x00000002;


		// ********************
		// Replica Modify fields
		// ********************
		public const uint DS_REPMOD_UPDATE_FLAGS = 0x00000001;
		public const uint DS_REPMOD_UPDATE_INSTANCE = 0x00000002;
		public const uint DS_REPMOD_UPDATE_ADDRESS = DS_REPMOD_UPDATE_INSTANCE;
		public const uint DS_REPMOD_UPDATE_SCHEDULE = 0x00000004;
		public const uint DS_REPMOD_UPDATE_RESULT = 0x00000008;
		public const uint DS_REPMOD_UPDATE_TRANSPORT = 0x00000010;

		// ********************
		// Update Refs fields
		// ********************
		/// <summary>
		/// Perform this operation asynchronously.
		/// </summary>
		public const uint DS_REPUPD_ASYNCHRONOUS_OPERATION = 0x00000001;
		/// <summary>
		/// The replica being deleted is writeable.
		/// </summary>
		public const uint DS_REPUPD_WRITEABLE = 0x00000002;
		/// <summary>
		/// Add a reference
		/// </summary>
		public const uint DS_REPUPD_ADD_REFERENCE = 0x00000004;
		/// <summary>
		/// Remove a reference
		/// </summary>
		public const uint DS_REPUPD_DELETE_REFERENCE = 0x00000008;
		/// <summary>
		/// Use GCSPN while notifying replica partner
		/// </summary>
		public const uint DS_REPUPD_REFERENCE_GCSPN = 0x00000010;


		// ********************
		//  NC Related Flags
		// ********************
		//
		// Instance Type bits, specifies flags for NC head creation.
		//
		/// <summary>
		/// This if what to specify on an object to indicate it's an NC Head.
		/// </summary>
		public const uint DS_INSTANCETYPE_IS_NC_HEAD = 0x00000001;
		/// <summary>
		/// This is to indicate that the NC Head is writeable.
		/// </summary>
		public const uint DS_INSTANCETYPE_NC_IS_WRITEABLE = 0x00000004;
		/// <summary>
		/// This is to indicate that this NC is still replicating in objects to this DC, and may not be a complete NC.
		/// </summary>
		public const uint DS_INSTANCETYPE_NC_COMING = 0x00000010;
		/// <summary>
		/// This is to indicate that this NC is in the process of being removed from this DC, and may not be a complete NC.
		/// </summary>
		public const uint DS_INSTANCETYPE_NC_GOING = 0x00000020;

		// ********************
		//  xxx_OPT_xxx Flags
		// ********************

		// These macros define bit flags which can be set in the "options" attribute
		// of objects of the specified object class.

		// Bit flags valid for options attribute on NTDS-DSA objects.
		//
		/// <summary>
		/// DSA is a global catalog
		/// </summary>
		public const uint NTDSDSA_OPT_IS_GC = (1 << 0);
		/// <summary>
		/// disable inbound replication
		/// </summary>
		public const uint NTDSDSA_OPT_DISABLE_INBOUND_REPL = (1 << 1);
		/// <summary>
		/// disable outbound replication
		/// </summary>
		public const uint NTDSDSA_OPT_DISABLE_OUTBOUND_REPL = (1 << 2);
		/// <summary>
		/// disable logical conn xlation
		/// </summary>
		public const uint NTDSDSA_OPT_DISABLE_NTDSCONN_XLATE = (1 << 3);
		/// <summary>
		/// disable SPN registration for ADAM
		/// </summary>
		public const uint NTDSDSA_OPT_DISABLE_SPN_REGISTRATION = (1 << 4);
		/// <summary>
		/// create own site topology
		/// </summary>
		public const uint NTDSDSA_OPT_GENERATE_OWN_TOPO = (1 << 5);

		// Bit flags for options attribute on NTDS-Connection objects.
		//
		// The reasons that two bits are required to control notification are as follows.
		// We must support existing connections with the old behavior and the UI does not
		// create manual connections with the new bit set.
		// The default for existing and manually created connections with bits 2 and 3
		// clear must be the standard prior behavior: notification for intra-site and
		// no notification for inter-site.
		// We need a way to distinguish a old connection which desires the default
		// notification rules, and a new connection for which we desire to explicitly
		// control the notification state as passed down from a site link.  Thus we
		// have a new bit to say we are overriding the default, and a new bit to indicate
		// what the overridden default shall be.
		//
		/// <summary>
		/// object generated by DS, not admin
		/// </summary>
		public const uint NTDSCONN_OPT_IS_GENERATED = (1 << 0);
		/// <summary>
		/// force sync in opposite direction at end of sync
		/// </summary>
		public const uint NTDSCONN_OPT_TWOWAY_SYNC = (1 << 1);
		/// <summary>
		/// Do not use defaults to determine notification
		/// </summary>
		public const uint NTDSCONN_OPT_OVERRIDE_NOTIFY_DEFAULT = (1 << 2);
		/// <summary>
		/// Does source notify destination
		/// </summary>
		public const uint NTDSCONN_OPT_USE_NOTIFY = (1 << 3);
		/// <summary>
		/// For intra-site connections, this bit has no meaning.
		/// For inter-site connections, this bit means:
		///  0 - Compression of replication data enabled
		///  1 - Compression of replication data disabled
		/// </summary>
		public const uint NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION = (1 << 4);
		/// <summary>
		/// For connections whose IS_GENERATED bit is 0, this bit has no effect.
		/// For KCC-generated connections, this bit indicates that the schedule attribute
		/// is owned by the user and should not be touched by the KCC.
		/// </summary>
		public const uint NTDSCONN_OPT_USER_OWNED_SCHEDULE = (1 << 5);
		/// <summary>
		/// This is the default rodc connection - 1 per rodc for FRS's uses
		/// </summary>
		public const uint NTDSCONN_OPT_RODC_TOPOLOGY = (1 << 6);

		// Connection reasons
		//
		// Values for "reason for connection".  A connection can be needed for
		// more than one reason.
		//
		/// <summary>
		/// 0x00000000
		/// </summary>
		public const uint NTDSCONN_KCC_NO_REASON = (0);
		/// <summary>
		/// 0x00000001
		/// </summary>
		public const uint NTDSCONN_KCC_GC_TOPOLOGY = (1 << 0);
		/// <summary>
		/// 0x00000002
		/// </summary>
		public const uint NTDSCONN_KCC_RING_TOPOLOGY = (1 << 1);
		/// <summary>
		/// 0x00000004
		/// </summary>
		public const uint NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY = (1 << 2);
		/// <summary>
		/// 0x00000008
		/// </summary>
		public const uint NTDSCONN_KCC_STALE_SERVERS_TOPOLOGY = (1 << 3);
		/// <summary>
		/// 0x00000010
		/// </summary>
		public const uint NTDSCONN_KCC_OSCILLATING_CONNECTION_TOPOLOGY = (1 << 4);
		/// <summary>
		/// 0x00000020
		/// </summary>
		public const uint NTDSCONN_KCC_INTERSITE_GC_TOPOLOGY = (1 << 5);
		/// <summary>
		/// 0x00000040
		/// </summary>
		public const uint NTDSCONN_KCC_INTERSITE_TOPOLOGY = (1 << 6);
		/// <summary>
		/// 0x00000080
		/// </summary>
		public const uint NTDSCONN_KCC_SERVER_FAILOVER_TOPOLOGY = (1 << 7);
		/// <summary>
		/// 0x00000100
		/// </summary>
		public const uint NTDSCONN_KCC_SITE_FAILOVER_TOPOLOGY = (1 << 8);
		/// <summary>
		/// 0x00000200
		/// </summary>
		public const uint NTDSCONN_KCC_REDUNDANT_SERVER_TOPOLOGY = (1 << 9);

		////
		//// The high 4 bits of the options attribute are used by NTFRS to assign priority
		//// for inbound connections. Bit 31 is used to force FRS to ignore schedule during
		//// the initial sync. Bits 30 - 28 are used to specify a priority between 0-7.
		////
		//public const int FRSCONN_PRIORITY_MASK = 0x70000000;
		//public const int FRSCONN_MAX_PRIORITY = 0x8;

		//public const int NTDSCONN_OPT_IGNORE_SCHEDULE_MASK = 0x80000000;

		//public const int NTDSCONN_IGNORE_SCHEDULE(_options_)
		//    (((_options_) & NTDSCONN_OPT_IGNORE_SCHEDULE_MASK) >> 31)

		//public const int FRSCONN_GET_PRIORITY(_options_)
		//    (((((_options_) & FRSCONN_PRIORITY_MASK) >> 28) != 0 ) ?
		//    (((_options_) & FRSCONN_PRIORITY_MASK) >> 28) :
		//    FRSCONN_MAX_PRIORITY
		//    )

		// Bit flags for options attribute on NTDS-Site-Settings objects.
		//
		/// <summary>
		/// automatic topology gen disabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED = (1 << 0);
		/// <summary>
		/// automatic topology cleanup disabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED = (1 << 1);
		/// <summary>
		/// automatic minimum hops topology disabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_TOPL_MIN_HOPS_DISABLED = (1 << 2);
		/// <summary>
		/// automatic stale server detection disabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED = (1 << 3);
		/// <summary>
		/// automatic inter-site topology gen disabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED = (1 << 4);
		/// <summary>
		/// group memberships for users enabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED = (1 << 5);
		/// <summary>
		/// force KCC to operate in Whistler behavior mode
		/// </summary>
		public const uint NTDSSETTINGS_OPT_FORCE_KCC_WHISTLER_BEHAVIOR = (1 << 6);
		/// <summary>
		/// force KCC to use the Windows 2000 ISTG election algorithm
		/// </summary>
		public const uint NTDSSETTINGS_OPT_FORCE_KCC_W2K_ELECTION = (1 << 7);
		/// <summary>
		/// prevent the KCC from randomly picking a bridgehead when creating a connection
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED = (1 << 8);
		/// <summary>
		/// allow the KCC to use hashing when creating a replication schedule
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_SCHEDULE_HASHING_ENABLED = (1 << 9);
		/// <summary>
		/// create static failover connections
		/// </summary>
		public const uint NTDSSETTINGS_OPT_IS_REDUNDANT_SERVER_TOPOLOGY_ENABLED = (1 << 10);
		// The following two options allow the new kcc spanning tree algorithm, which replaces the ISM,
		// to override the ISM policy settings. These two flags are analogous to those found on the
		// transport object.
		/// <summary>
		/// default without flag: schedules are significant
		/// This flag causes the KCC in W2K3 mode to ignore schedules
		/// Schedules disabled
		/// </summary>
		public const uint NTDSSETTINGS_OPT_W2K3_IGNORE_SCHEDULES = (1 << 11);
		/// <summary>
		/// default without flag: links transitive (bridges not required) auto site link bridging enabled
		/// This flag causes the KCC in W2K3 mode to require bridges
		/// siteLink bridges are required
		/// </summary>
		public const uint NTDSSETTINGS_OPT_W2K3_BRIDGES_REQUIRED = (1 << 12);
		/// <summary>
		/// How many redundant connections will be generated
		/// </summary>
		public const uint NTDSSETTINGS_DEFAULT_SERVER_REDUNDANCY = 2;

		// Bit flags for options attribute on Inter-Site-Transport objects
		//
		// Note, the sense of the flag should be such that the default state or
		// behavior corresponds to the flag NOT being present. Put another way, the
		// flag should state the OPPOSITE of the default
		// 
		/// <summary>
		/// Schedules disabled
		/// default: schedules are significant
		/// </summary>
		public const uint NTDSTRANSPORT_OPT_IGNORE_SCHEDULES = (1 << 0);
		/// <summary>
		/// siteLink bridges are required
		/// default: links transitive (bridges not required)
		/// </summary>
		public const uint NTDSTRANSPORT_OPT_BRIDGES_REQUIRED = (1 << 1); // 

		// Bit flags for options attribute on site-Connection objects
		//
		// These are not realized in the DS, but are built up in the KCC
		/// <summary>
		/// Use notification on this link
		/// </summary>
		public const uint NTDSSITECONN_OPT_USE_NOTIFY = (1 << 0);
		/// <summary>
		/// force sync in opposite direction at end of sync
		/// </summary>
		public const uint NTDSSITECONN_OPT_TWOWAY_SYNC = (1 << 1);
		/// <summary>
		/// This bit means:
		///  0 - Compression of replication data across this site connection enabled
		///  1 - Compression of replication data across this site connection disabled
		/// </summary>
		public const uint NTDSSITECONN_OPT_DISABLE_COMPRESSION = (1 << 2);

		// Bit flags for options attribute on site-Link objects
		// Note that these options are AND-ed along a site-link path
		//
		/// <summary>
		/// Use notification on this link
		/// </summary>
		public const uint NTDSSITELINK_OPT_USE_NOTIFY = (1 << 0);
		/// <summary>
		/// force sync in opposite direction at end of sync
		/// </summary>
		public const uint NTDSSITELINK_OPT_TWOWAY_SYNC = (1 << 1);
		/// <summary>
		/// This bit means:
		///  0 - Compression of replication data across this site link enabled
		///  1 - Compression of replication data across this site link disabled
		/// </summary>
		public const uint NTDSSITELINK_OPT_DISABLE_COMPRESSION = (1 << 2);

		// ***********************
		// Well Known Object Guids
		// ***********************
		static public readonly Guid GUID_USERS_CONTAINER = new Guid("a9d1ca15768811d1aded00c04fd8d5cd");
		static public readonly Guid GUID_COMPUTRS_CONTAINER = new Guid("aa312825768811d1aded00c04fd8d5cd");
		static public readonly Guid GUID_SYSTEMS_CONTAINER = new Guid("ab1d30f3768811d1aded00c04fd8d5cd");
		static public readonly Guid GUID_DOMAIN_CONTROLLERS_CONTAINER = new Guid("a361b2ffffd211d1aa4b00c04fd7d83a");
		static public readonly Guid GUID_INFRASTRUCTURE_CONTAINER = new Guid("2fbac1870ade11d297c400c04fd8d5cd");
		static public readonly Guid GUID_DELETED_OBJECTS_CONTAINER = new Guid("18e2ea80684f11d2b9aa00c04f79f805");
		static public readonly Guid GUID_LOSTANDFOUND_CONTAINER = new Guid("ab8153b7768811d1aded00c04fd8d5cd");
		static public readonly Guid GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER = new Guid("22b70c67d56e4efb91e9300fca3dc1aa");
		static public readonly Guid GUID_PROGRAM_DATA_CONTAINER = new Guid("09460c08ae1e4a4ea0f64aee7daa1e5a");
		static public readonly Guid GUID_MICROSOFT_PROGRAM_DATA_CONTAINER = new Guid("f4be92a4c777485e878e9421d53087db");
		static public readonly Guid GUID_NTDS_QUOTAS_CONTAINER = new Guid("6227f0af1fc2410d8e3bb10615bb5b0f");

		public enum DS_MANGLE_FOR : uint
		{
			DS_MANGLE_UNKNOWN = 0,
			DS_MANGLE_OBJECT_RDN_FOR_DELETION,
			DS_MANGLE_OBJECT_RDN_FOR_NAME_CONFLICT
		};
		#endregion

		#region Prototypes
		#region Bind/Unbind
		/// <summary>
		/// The DsBind function binds to a domain controller.DsBind uses the default process credentials to bind to the domain controller. To specify alternate credentials, use the DsBindWithCred function.
		/// </summary>
		/// <param name="DomainControllerName">(optional)Pointer to a null-terminated string that contains the name of the domain controller to bind to. This name can be the name of the domain controller or the fully-qualified DNS name of the domain controller. Either name type can, optionally, be preceded by two backslash characters. All of the following examples represent correctly formatted domain controller names:
		/// <para>	"FAB-DC-01"</para>
		/// <para>	"\\FAB-DC-01"</para>
		/// <para>	"FAB-DC-01.fabrikam.com"</para>
		/// <para>	"\\FAB-DC-01.fabrikam.com"</para>
		/// <para>This parameter can be NULL. For more information, see Remarks.</para>
		/// </param>
		/// <param name="DnsDomainName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind to. This parameter can be NULL. For more information, see Remarks.</param>
		/// <param name="phDS">Address of a DsHandle value that receives the binding handle. To close this handle, pass it to the DsUnBind function.</param>
		/// <returns>Returns ERROR_SUCCESS if successful or a Windows or RPC error code otherwise. The following are the most common error codes.
		/// <para>ERROR_INVALID_PARAMETER - phDS is invalid.</para>
		/// <para>ERROR_NO_SUCH_DOMAIN - No domain controller (DC) is available for the specified domain or the domain does not exist.</para>
		/// <para>ERROR_INVALID_DOMAINNAME - The format of the specified DnsDomainName is invalid.</para>
		/// <para>ERROR_NOT_ENOUGH_MEMORY - Insufficient memory available.</para>
		/// </returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBind", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBind(
			[MarshalAs(UnmanagedType.LPTStr)] string DomainControllerName
			, [MarshalAs(UnmanagedType.LPTStr)] string DnsDomainName
			, out DsHandle phDS);

		/// <summary>
		/// The DsBindWithCred function binds to a domain controller using the specified credentials.
		/// </summary>
		/// <param name="DomainControllerName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind. For more information about this parameter, see the DomainControllerName description in the DsBind topic.</param>
		/// <param name="DnsDomainName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind to. For more information about this parameter, see the DnsDomainName description in the DsBind topic.</param>
		/// <param name="AuthIdentity">(optional)Contains an RPC_AUTH_IDENTITY_HANDLE value that represents the credentials to be used for the bind. The DsMakePasswordCredentials function is used to obtain this value. If this parameter is NULL, the credentials of the calling thread are used.
		/// <para>DsUnBind must be called before freeing this handle with the DsFreePasswordCredentials function.</para>
		/// </param>
		/// <param name="phDS">Address of a DsHandle value that receives the binding handle. To close this handle, pass it to the DsUnBind function.</param>
		/// <returns>Returns ERROR_SUCCESS if successful or a Windows or RPC error code otherwise.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBindWithCred", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBindWithCred(
			[MarshalAs(UnmanagedType.LPWStr)] string DomainControllerName
			, [MarshalAs(UnmanagedType.LPWStr)] string DnsDomainName
			, [MarshalAs(UnmanagedType.Struct)] RPC_AUTH_IDENTITY_HANDLE AuthIdentity
		   , DsHandle phDS);

		/// <summary>
		/// The DsBindWithSpn function binds to a domain controller using the specified credentials and a specific service principal name (SPN) for mutual authentication.
		/// <para>This function is provided for where complete control is required for mutual authentication. Do not use this function if you expect DsBind to find a server for you, because SPNs are computer-specific, and it is unlikely that the SPN you provide will match the server that DsBind finds for you. Providing a NULL ServicePrincipalName argument results in behavior that is identical to DsBindWithCred.</para>
		/// </summary>
		/// <param name="DomainControllerName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind to. For more information, see the DomainControllerName description in the DsBind topic.</param>
		/// <param name="DnsDomainName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind to. For more information, see the DnsDomainName description in the DsBind topic.</param>
		/// <param name="AuthIdentity">(optional)Contains an RPC_AUTH_IDENTITY_HANDLE value that represents the credentials to be used for the bind. The DsMakePasswordCredentials function is used to obtain this value. If this parameter is NULL, the credentials of the calling thread are used.
		/// <para>DsUnBind must be called before freeing this handle with the DsFreePasswordCredentials function.</para>
		/// </param>
		/// <param name="ServicePrincipalName">(optional)Pointer to a null-terminated string that specifies the Service Principal Name to assign to the client. Passing NULL in ServicePrincipalName is equivalent to a call to the DsBindWithCred function.</param>
		/// <param name="phDS">Address of a DsHandle value that receives the binding handle. To close this handle, pass it to the DsUnBind function</param>
		/// <returns></returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBindWithSpn", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBindWithSpn(
			[MarshalAs(UnmanagedType.LPWStr)] string DomainControllerName
			, [MarshalAs(UnmanagedType.LPWStr)] string DnsDomainName
			, [MarshalAs(UnmanagedType.Struct)] RPC_AUTH_IDENTITY_HANDLE AuthIdentity
		   , [MarshalAs(UnmanagedType.LPWStr)] string ServicePrincipalName
		   , DsHandle phDS);

		/// <summary>
		/// The DsBindWithSpnEx function binds to a domain controller using the specified credentials and a specific service principal name (SPN) for mutual authentication. This function is similar to the DsBindWithSpn function except this function allows more binding options with the BindFlags parameter.
		/// <para>This function is provided where complete control is required over mutual authentication. Do not use this function if you expect DsBind to find a server for you, because SPNs are computer-specific, and it is unlikely that the SPN you provide will match the server that DsBind finds for you. Providing a NULL ServicePrincipalName argument results in behavior that is identical to DsBindWithCred.</para>
		/// </summary>
		/// <param name="DomainControllerName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind. For more information, see the DomainControllerName description in the DsBind topic.</param>
		/// <param name="DnsDomainName">(optional)Pointer to a null-terminated string that contains the fully-qualified DNS name of the domain to bind. For more information, see the DnsDomainName description in the DsBind topic.</param>
		/// <param name="AuthIdentity">(optional)Contains an RPC_AUTH_IDENTITY_HANDLE value that represents the credentials to be used for the bind. The DsMakePasswordCredentials function is used to obtain this value. If this parameter is NULL, the credentials of the calling thread are used.</param>
		/// <param name="ServicePrincipalName">(optional)Pointer to a null-terminated string that specifies the Service Principal Name to assign to the client. Passing NULL in ServicePrincipalName is equivalent to a call to the DsBindWithCred function.</param>
		/// <param name="BindFlags">(optional)Contains a set of flags that define the behavior of this function. This parameter can contain zero or a combination of the values listed in the following table.
		/// <para>NTDSAPI_BIND_ALLOW_DELEGATION, NTDSAPI_BIND_FIND_BINDING, NTDSAPI_BIND_FORCE_KERBEROS</para></param>
		/// <param name="phDS">Address of a DsHandle value that receives the binding handle. To close this handle, pass it to the DsUnBind function</param>
		/// <returns>Returns ERROR_SUCCESS if successful or a Windows or RPC error code otherwise.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBindWithSpnEx", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBindWithSpnEx(
			[MarshalAs(UnmanagedType.LPWStr)] string DomainControllerName
			, [MarshalAs(UnmanagedType.LPWStr)] string DnsDomainName
			, [MarshalAs(UnmanagedType.Struct)] RPC_AUTH_IDENTITY_HANDLE AuthIdentity
		   , [MarshalAs(UnmanagedType.LPWStr)] string ServicePrincipalName
		   , DWORD BindFlags
		   , DsHandle phDS);

		/// <summary>
		/// The DsBindByInstance function explicitly binds to any AD LDS or Active Directory instance.
		/// </summary>
		/// <param name="ServerName">(optional)Pointer to a null-terminated string that specifies the name of the instance. This parameter is required to bind to an AD LDS instance. If this parameter is NULL when binding to an Active Directory instance, then the DnsDomainName parameter must contain a value. If this parameter and the DnsDomainName parameter are both NULL, the function fails with the return value ERROR_INVALID_PARAMETER (87).</param>
		/// <param name="Annotation">(optional)Pointer to a null-terminated string that specifies the port number of the AD LDS instance or NULL when binding to an Active Directory instance. For example, "389".
		/// <para>If this parameter is NULL when binding by domain to an Active Directory instance, then the DnsDomainName parameter must be specified. If this parameter is NULL when binding to an AD LDS instance, then the InstanceGuid parameter must be specified.</para></param>
		/// <param name="InstanceGuid">(optional)Pointer to a GUID value that contains the GUID of the AD LDS instance. The GUID value is the objectGUID property of the nTDSDSA object of the instance. If this parameter is NULL when binding to an AD LDS instance, the Annotation parameter must be specified.</param>
		/// <param name="DnsDomainName">(optional)Pointer to a null-terminated string that specifies the DNS name of the domain when binding to an Active Directory instance by domain. Set this parameter to NULL to bind to an Active Directory instance by server or to an AD LDS instance.</param>
		/// <param name="AuthIdentity">(optional)Handle to the credentials used to start the RPC session. Use the DsMakePasswordCredentials function to create a structure suitable for AuthIdentity.</param>
		/// <param name="ServicePrincipalName">(optional)Pointer to a null-terminated string that specifies the Service Principal Name to assign to the client. Passing NULL in ServicePrincipalName is equivalent to a call to the DsBindWithCred function.</param>
		/// <param name="BindFlags">(optional)Contains a set of flags that define the behavior of this function. This parameter can contain zero or a combination of the values listed in the following table.
		/// <para>NTDSAPI_BIND_ALLOW_DELEGATION, NTDSAPI_BIND_FIND_BINDING, NTDSAPI_BIND_FORCE_KERBEROS</para></param>
		/// <param name="phDS">Address of a DsHandle value that receives the bind handle. To close this handle, call DsUnBind.</param>
		/// <returns>Returns NO_ERROR if successful or an RPC or Win32 error otherwise.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBindByInstance", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBindByInstance(
			[MarshalAs(UnmanagedType.LPWStr)] string ServerName
			, [MarshalAs(UnmanagedType.LPWStr)] string Annotation
			, [MarshalAs(UnmanagedType.Struct)] Guid InstanceGuid
			, [MarshalAs(UnmanagedType.LPWStr)] string DnsDomainName
			, [MarshalAs(UnmanagedType.Struct)] RPC_AUTH_IDENTITY_HANDLE AuthIdentity
		   , [MarshalAs(UnmanagedType.LPWStr)] string ServicePrincipalName
		   , DWORD BindFlags
		   , DsHandle phDS);

		/// <summary>
		/// The DsBindToISTG function binds to the computer that holds the Inter-Site Topology Generator (ISTG) role in the domain of the local computer. This function is used to obtain the bind handle for use with the DsQuerySitesByCost function.
		/// </summary>
		/// <param name="SiteName">(optional)Pointer to a null-terminated string that contains the site name used when binding. If this parameter is NULL, the site of the nearest domain controller is used.</param>
		/// <param name="phDS">Address of a DsHandle value that receives the bind handle. To close this handle, call DsUnBind.</param>
		/// <returns>Returns ERROR_SUCCESS if successful or a Win32 or RPC error code otherwise.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBindToISTG", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBindToISTG(
			[MarshalAs(UnmanagedType.LPWStr)] string SiteName
			, DsHandle phDS);

		/// <summary>
		/// The DsBindingSetTimeout function sets the timeout value that is honored by all RPC calls that use the specified binding handle. RPC calls that required more time than the timeout value are canceled.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the DSBind or DSBindWithCred function.</param>
		/// <param name="cTimeoutSecs">Contains the new timeout value, in seconds.</param>
		/// <returns>Returns ERROR_SUCCESS if successful or a Win32 or RPC error code otherwise.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsBindingSetTimeout", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsBindingSetTimeout(
			DsHandle hDS
			, ULONG cTimeoutSecs);

		/// <summary>
		/// The DsUnBind function finds an RPC session with a domain controller and unbinds a handle to the directory service (DS).
		/// </summary>
		/// <param name="phDS">Pointer to a bind handle to the directory service. This handle is provided by a call to DsBind, DsBindWithCred, or DsBindWithSpn.</param>
		/// <returns>NO_ERROR</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsUnBind", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static private extern DWORD DsUnBind(
			IntPtr phDS);
		#endregion

		#region Password credentials
		/// <summary>
		/// The DsMakePasswordCredentials function constructs a credential handle suitable for use with the DsBindWithCred function.
		/// </summary>
		/// <param name="User">Pointer to a null-terminated string that contains the user name to use for the credentials.</param>
		/// <param name="Domain">Pointer to a null-terminated string that contains the domain that the user is a member of.</param>
		/// <param name="Password">Pointer to a null-terminated string that contains the password to use for the credentials.</param>
		/// <param name="pAuthIdentity">Pointer to an RPC_AUTH_IDENTITY_HANDLE value that receives the credential handle. This handle is used in a subsequent call to DsBindWithCred. This handle must be freed with the DsFreePasswordCredentials function when it is no longer required.</param>
		/// <returns>Returns a Win32 error code</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsMakePasswordCredentials", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsMakePasswordCredentials(
			[MarshalAs(UnmanagedType.LPWStr)] string User
			, [MarshalAs(UnmanagedType.LPWStr)] string Domain
			, [MarshalAs(UnmanagedType.LPWStr)] string Password
			, RPC_AUTH_IDENTITY_HANDLE pAuthIdentity);

		/// <summary>
		/// The DsFreePasswordCredentials function frees memory allocated for a credentials structure by the DsMakePasswordCredentials function.
		/// </summary>
		/// <param name="AuthIdentity">Handle of the credential structure to be freed.</param>
		/// <returns>This function does not return a value. </returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsFreePasswordCredentials", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static private extern void DsFreePasswordCredentials(RPC_AUTH_IDENTITY_HANDLE AuthIdentity);
		#endregion

		#region Crack Names
		/// <summary>
		/// The DsCrackNames function converts an array of directory service object names from one format to another. Name conversion enables client applications to map between the multiple names used to identify various directory service objects. For example, user objects can be identified by SAM account names (domain\username), user principal name (username@domain.com), or distinguished name.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the DSBind or DSBindWithCred function. If flags contains DS_NAME_FLAG_SYNTACTICAL_ONLY, hDS can be NULL.</param>
		/// <param name="flags">Contains one or more of the DS_NAME_FLAGS values used to determine how the name syntax will be cracked.</param>
		/// <param name="formatOffered">Contains one of the DS_NAME_FORMAT values that identifies the format of the input names.
		/// <para></para><para>The DS_LIST_NCS value can also be passed for this parameter. This causes DsCrackNames to return the distinguished names of all naming contexts in the current forest. The formatDesired parameter is ignored. cNames must be at least one and all strings in rpNames must have a length greater than zero characters. The contents of the rpNames strings is ignored.</para>
		/// <para>Note  DS_LIST_NCS is not defined in a published header file. To use this value, define it as follows.</para>
		/// <para>DS_LIST_NCS = 0xfffffff6</para>
		/// </param>
		/// <param name="formatDesired">Contains one of the DS_NAME_FORMAT values that identifies the format of the output names. The DS_SID_OR_SID_HISTORY_NAME value is not supported.</param>
		/// <param name="cNames">Contains the number of elements in the rpNames array.</param>
		/// <param name="rpNames">Pointer to an array of pointers to null-terminated strings that contain names to be converted.</param>
		/// <param name="ppResult">Pointer to a PDS_NAME_RESULT value that receives a DS_NAME_RESULT structure that contains the converted names. The caller must free this memory, when it is no longer required, by calling DsFreeNameResult.</param>
		/// <returns>Returns a Win32 error value, an RPC error value</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsCrackNames", SetLastError = false, ThrowOnUnmappableChar = true)]
		static public extern DWORD DsCrackNames(
			DsHandle hDS
			, DS_NAME_FLAGS flags
			, DS_NAME_FORMAT formatOffered
			, DS_NAME_FORMAT formatDesired
			, DWORD cNames
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 4)] string[] rpNames
			, out DS_NAME_RESULT ppResult);

		/// <summary>
		/// The DsFreeNameResult function frees the memory held by a DS_NAME_RESULT structure. Use this function to free the memory allocated by the DsCrackNames function.
		/// </summary>
		/// <param name="pResult">Pointer to the DS_NAME_RESULT structure to be freed.</param>
		/// <returns>This function does not return a value.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsFreeNameResult", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern void DsFreeNameResult(DS_NAME_RESULT pResult);
		#endregion

		#region SPN management
		/// <summary>
		/// The DsMakeSpn function constructs a service principal name (SPN) that identifies a service instance.
		/// <para>A client application uses this function to compose an SPN, which it uses to authenticate the service instance. For example, the client can pass an SPN in the pszTargetName parameter of the InitializeSecurityContext function.</para>
		/// </summary>
		/// <param name="ServiceClass">Pointer to a constant null-terminated string that specifies the class of the service. This parameter can be any string unique to that service; either the protocol name, for example, ldap, or the string form of a GUID are acceptable.</param>
		/// <param name="ServiceName">Pointer to a constant null-terminated string that specifies the DNS name, NetBIOS name, or distinguished name (DN). This parameter must be non-NULL. 
		/// <para>For more information about how the ServiceName, InstanceName and InstancePort parameters are used to compose an SPN, see the following Remarks section.</para>
		/// </param>
		/// <param name="InstanceName">Pointer to a constant null-terminated string that specifies the DNS name or IP address of the host for an instance of the service. 
		/// <para>If ServiceName specifies the DNS or NetBIOS name of the service host computer, the InstanceName parameter must be NULL.</para>
		/// <para>If ServiceName specifies a DNS domain name, the name of a DNS SRV record, or a distinguished name, such as the DN of a service connection point, the InstanceName parameter must specify the DNS or NetBIOS name of the service host computer.</para>
		/// </param>
		/// <param name="InstancePort">Port number for an instance of the service. Use 0 for the default port. If this parameter is zero, the SPN does not include a port number.</param>
		/// <param name="Referrer">Pointer to a constant null-terminated string that specifies the DNS name of the host that gave an IP address referral. This parameter is ignored unless the ServiceName parameter specifies an IP address.</param>
		/// <param name="pcSpnLenght">Pointer to a variable that contains the length, in characters, of the buffer that will receive the new constructed SPN. This value may be 0 to request the final buffer size in advance. 
		/// <para>The pcSpnLength parameter also receives the actual length of the SPN created, including the terminating null character.</para>
		/// </param>
		/// <param name="pszSpn">Pointer to a null-terminated string that receives the constructed SPN. This buffer should be the length specified by pcSpnLength. The pszSpn parameter may be NULL to request the final buffer size in advance.</param>
		/// <returns>If the function returns an SPN, the return value is ERROR_SUCCESS.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsMakeSpn", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsMakeSpn(
			[MarshalAs(UnmanagedType.LPWStr)] string ServiceClass
			, [MarshalAs(UnmanagedType.LPWStr)] string ServiceName
			, [MarshalAs(UnmanagedType.LPWStr)] string InstanceName
			, USHORT InstancePort
			, [MarshalAs(UnmanagedType.LPWStr)] string Referrer
			, ref DWORD pcSpnLength
			, [MarshalAs(UnmanagedType.LPWStr)] out string pszSpn);

		/// <summary>
		/// The DsGetSpn function constructs an array of one or more service principal names (SPNs). Each name in the array identifies an instance of a service. These SPNs may be registered with the directory service (DS) using the DsWriteAccountSpn function.
		/// </summary>
		/// <param name="ServiceType">Identifies the format of the SPNs to compose via <see cref="DS_SPN_NAME_TYPE"/></param>
		/// <param name="ServiceClass">Pointer to a constant null-terminated string that specifies the class of the service; for example, http. Generally, this can be any string that is unique to the service.</param>
		/// <param name="ServiceName">Pointer to a constant null-terminated string that specifies the DNS name or distinguished name (DN) of the service. ServiceName is not required for a host-based service. For more information, see the description of the ServiceType parameter for the possible values of ServiceName.</param>
		/// <param name="InstancePort">Specifies the port number of the service instance. If this value is zero, the SPN does not include a port number.</param>
		/// <param name="cInstanceNames">Specifies the number of elements in the pInstanceNames and pInstancePorts arrays. If this value is zero, pInstanceNames must point to an array of cInstanceNames strings, and pInstancePorts can be either NULL or a pointer to an array of cInstanceNames port numbers. If this value is zero, DsGetSpn returns only one SPN in the prpszSpn array and pInstanceNames and pInstancePorts are ignored.</param>
		/// <param name="pInstanceNames">Pointer to an array of null-terminated strings that specify extra instance names (not used for host names). This parameter is ignored if cInstanceNames is zero. In that case, the InstanceName component of the SPN defaults to the fully-qualified DNS name of the local computer or the NetBIOS name if DS_SPN_NB_HOST or DS_SPN_NB_DOMAIN is specified.</param>
		/// <param name="pInstancePorts">Pointer to an array of extra instance ports. If this value is non-NULL, it must point to an array of cInstanceNames port numbers. If this value is NULL, the SPNs do not include a port number. This parameter is ignored if cInstanceNames is zero.</param>
		/// <param name="pcSpn">Pointer to a variable that receives the number of SPNs contained in prpszSPN.</param>
		/// <param name="prpszSpn">Pointer to a variable that receives a pointer to an array of SPNs. This array must be freed with DsFreeSpnArray.</param>
		/// <returns>If the function returns an array of SPNs, the return value is ERROR_SUCCESS.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsGetSpn", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsGetSpn(
			DS_SPN_NAME_TYPE ServiceType
			, [MarshalAs(UnmanagedType.LPWStr)] string ServiceClass
			, [MarshalAs(UnmanagedType.LPWStr)] string ServiceName
			, USHORT InstancePort
			, USHORT cInstanceNames
			, [MarshalAs(UnmanagedType.LPWStr)] string pInstanceNames
			, USHORT pInstancePorts
			, out DWORD pcSpn
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 7)] out string[] prpszSpn);

		/// <summary>
		/// The DsFreeSpnArray function frees an array returned from the DsGetSpn function.
		/// </summary>
		/// <param name="cSpn">Specifies the number of elements contained in rpszSpn.</param>
		/// <param name="rpszSpn">Pointer to an array returned from DsGetSpn.</param>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsFreeSpnArray", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern void DsFreeSpnArray(
			DWORD cSpn
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0)] string[] rpszSpn);

		/// <summary>
		/// The DsCrackSpn function parses a service principal name (SPN) into its component strings.
		/// </summary>
		/// <param name="pszSpn">Pointer to a constant null-terminated string that contains the SPN to parse. The SPN has the following format, in which the &lt;service class&gt; and &lt;instance name&gt; components must be present and the &lt;port number&gt; and &lt;service name&gt; components are optional. The &lt;port number&gt; component must be a numeric string value. </param>
		/// <param name="pcServiceClass">Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the ServiceClass buffer, including the terminating null character. On exit, this parameter contains the number of TCHARs in the ServiceClass string, including the terminating null character.
		/// <para>If this parameter is null, contains zero, or ServiceClass is null, this parameter and ServiceClass are ignored.</para>
		/// <para>To obtain the number of characters required for the ServiceClass string, including the null terminator, call this function with a valid SPN, a non-null ServiceClass and this parameter set to 1.</para>
		/// </param>
		/// <param name="ServiceClass">Pointer to a TCHAR buffer that receives a null-terminated string containing the &lt;service class&gt; component of the SPN. This buffer must be at least *pcServiceClass TCHARs in size. This parameter may be NULL if the service class is not required.</param>
		/// <param name="pcServiceName">Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the ServiceName buffer, including the terminating null character. On exit, this parameter contains the number of TCHARs in the ServiceName string, including the terminating null character. 
		/// <para>If this parameter is null, contains zero, or ServiceName is null, this parameter and ServiceName are ignored.</para>
		/// <para>To obtain the number of characters required for the ServiceName string, including the null terminator, call this function with a valid SPN, a non-null ServiceName and this parameter set to 1.</para>
		/// </param>
		/// <param name="ServiceName">Pointer to a TCHAR buffer that receives a null-terminated string containing the &lt;service name&gt; component of the SPN. This buffer must be at least *pcServiceName TCHARs in size. If the &lt;service name&gt; component is not present in the SPN, this buffer receives the &lt;instance name&gt; component. This parameter may be NULL if the service name is not required.</param>
		/// <param name="pcInstanceName">Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the InstanceName buffer, including the terminating null character. On exit, this parameter contains the number of TCHARs in the InstanceName string, including the terminating null character.
		/// <para>If this parameter is null, contains zero, or InstanceName is null, this parameter and InstanceName are ignored.</para>
		/// <para>To obtain the number of characters required for the InstanceName string, including the null terminator, call this function with a valid SPN, a non-null InstanceName and this parameter set to 1.</para>
		/// </param>
		/// <param name="InstanceName">Pointer to a TCHAR buffer that receives a null-terminated string containing the &lt;instance name&gt; component of the SPN. This buffer must be at least *pcInstanceName TCHARs in size. This parameter may be NULL if the instance name is not required.</param>
		/// <param name="pInstancePort">Pointer to a DWORD value that receives the integer value of the &lt;port number&gt; component of the SPN. If the SPN does not contain a &lt;port number&gt; component, this parameter receives zero. This parameter may be NULL if the port number is not required.</param>
		/// <returns></returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsCrackSpn", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsCrackSpn(
			[MarshalAs(UnmanagedType.LPWStr)] string pszSpn
			, ref DWORD pcServiceClass
			, [MarshalAs(UnmanagedType.LPWStr)] out StringBuilder ServiceClass
			, ref DWORD pcServiceName
			, [MarshalAs(UnmanagedType.LPWStr)] out StringBuilder ServiceName
			, ref DWORD pcInstanceName
			, [MarshalAs(UnmanagedType.LPWStr)] out StringBuilder InstanceName
			, out USHORT pInstancePort);

		/// <summary>
		/// The DsWriteAccountSpn function writes an array of service principal names (SPNs) to the servicePrincipalName attribute of a specified user or computer account object in Active Directory Domain Services. The function can either register or unregister the SPNs.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/>DSBindWithCred function.</param>
		/// <param name="Operation">Contains one of the <see cref="DS_SPN_WRITE_OP"/> values that specifies the operation that <see cref="DsWriteAccountSpn"/> will perform.</param>
		/// <param name="pszAccount">Pointer to a constant null-terminated string that specifies the distinguished name of a user or computer object in Active Directory Domain Services. The caller must have write access to the servicePrincipalName property of this object.</param>
		/// <param name="cSpn">Specifies the number of SPNs in rpszSpn. If this value is zero, and Operation contains <see cref="DS_SPN_REPLACE_SPN_OP"/>, the function removes all values from the servicePrincipalName attribute of the specified account.</param>
		/// <param name="rpszSpn">Pointer to an array of constant null-terminated strings that specify the SPNs to be added to or removed from the account identified by the pszAccount parameter. The <see cref="DsGetSpn"/> function is used to compose SPNs for a service.</param>
		/// <returns>Returns ERROR_SUCCESS if successful or a Win32, RPC or directory service error if unsuccessful.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsWriteAccountSpn", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsWriteAccountSpn(
			DsHandle hDS
			, DS_SPN_WRITE_OP Operation
			, [MarshalAs(UnmanagedType.LPWStr)] string pszAccount
			, DWORD cSpn
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 3)] string rpszSpn);

		/// <summary>
		/// The DsClientMakeSpnForTargetServer function constructs a service principal name (SPN) that identifies a specific server to use for authentication.
		/// </summary>
		/// <param name="ServiceClass">Pointer to a null-terminated string that contains the class of the service as defined by the service. This can be any string unique to the service.</param>
		/// <param name="ServiceName">Pointer to a null-terminated string that contains the distinguished name service (DNS) host name. This can either be a fully-qualified name or an IP address in the Internet standard format.
		/// <para>Use of an IP address for ServiceName is not recommended because this can create a security issue. Before the SPN is constructed, the IP address must be translated to a computer name through DNS name resolution. It is possible for the DNS name resolution to be spoofed, replacing the intended computer name with an unauthorized computer name.</para>
		/// </param>
		/// <param name="pcSpnLength">Pointer to a DWORD value that, on entry, contains the size of the pszSpn buffer, in characters. On output, this parameter receives the number of characters copied to the pszSpn buffer, including the terminating NULL.</param>
		/// <param name="pszSpn">Pointer to a string buffer that receives the SPN.</param>
		/// <returns>This function returns standard Win32 error codes.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsClientMakeSpnForTargetServer", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsClientMakeSpnForTargetServer(
			[MarshalAs(UnmanagedType.LPWStr)] string ServiceClass
			, [MarshalAs(UnmanagedType.LPWStr)] string ServiceName
			, ref DWORD pcSpnLength
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] pszSpn);

		/// <summary>
		/// The DsServerRegisterSpn function composes two SPNs for a host-based service. The names are based on the DNS and NetBIOS names of the local computer. The function modifies the servicePrincipalName attribute of either a specified account or of the account associated with the calling thread. The function either registers or unregisters the SPNs.
		/// <para>A host-based service is a service instance that provides services identified with its host computer, as distinguished from a replicable service where clients have no preference which host computer a service instance runs on.</para>
		/// </summary>
		/// <param name="Operation">Specifies what operation DsServerRegisterSpn should perform. This parameter can have one of the values from the <see cref="DS_SPN_WRITE_OP"/> enum.</param>
		/// <param name="ServiceClass">Pointer to a constant null-terminated string specifying the class of the service. This parameter may be any string unique to that service; either the protocol name (for example, ldap) or the string form of a GUID will work.</param>
		/// <param name="UserObjectDn">Pointer to a constant null-terminated string specifying the distinguished name of a user or computer account object to write the SPNs to. If this parameter is NULL, <see cref="DsServerRegisterSpn"/> writes to the account object of the primary or impersonated user associated with the calling thread. If the thread is running in the security context of the LocalSystem account, the function writes to the account object of the local computer.</param>
		/// <returns>If the function successfully registers one or more SPNs, it returns ERROR_SUCCESS. Modification is performed permissively, so that adding a value that already exists does not return an error.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsServerRegisterSpn", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsServerRegisterSpn(
			DS_SPN_WRITE_OP Operation
			, [MarshalAs(UnmanagedType.LPWStr)] string ServiceClass
			, [MarshalAs(UnmanagedType.LPWStr)] string UserObjectDn);
		#endregion

		#region Manage replication
		/// <summary>
		/// The DsReplicaSync function synchronizes a destination naming context (NC) with one of its sources.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/> function.</param>
		/// <param name="NameContext">Pointer to a constant null-terminated string that specifies the distinguished name of the destination NC.</param>
		/// <param name="pUuidDsaSrc">Pointer to the UUID of a source that replicates to the destination NC.</param>
		/// <param name="Options"></param>
		/// <returns></returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaSync", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaSync(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string NameContext
			, [MarshalAs(UnmanagedType.LPStruct)] Guid pUuidDsaSrc
			, ULONG Options);

		/// <summary>
		/// The DsReplicaAdd function adds a replication source reference to a destination naming context.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/> function.</param>
		/// <param name="NameContext">The null-terminated string that specifies the distinguished name (DN) of the destination naming context (NC) for which to add the replica. The destination NC record must exist locally as either an object, instantiated or not, or a reference phantom, for example, a phantom with a GUID.</param>
		/// <param name="SourceDsaDn">The null-terminated string that specifies the DN of the NTDS-DSA object for the source directory system agent. This parameter is required if Options includes <see cref="DS_REPADD_ASYNCHRONOUS_REPLICA"/>; otherwise, it is ignored.</param>
		/// <param name="TransportDn">The null-terminated string that specifies the DN of the interSiteTransport object that represents the transport used for communication with the source server. This parameter is required if Options includes <see cref="DS_REPADD_INTERSITE_MESSAGING"/>; otherwise, it is ignored.</param>
		/// <param name="SourceDsaAddress">The null-terminated string that specifies the transport-specific address of the source DSA. This source server is identified by a string name, not by its UUID. A string name appropriate for SourceDsaAddress is usually a DNS name based on a GUID, where the GUID part of the name is the GUID of the NTDS-DSA object for the source server.</param>
		/// <param name="pSchedule">Pointer to a <see cref="SCHEDULE"/> structure that contains the replication schedule data for the replication source. This parameter is optional and can be NULL if not used.</param>
		/// <param name="Options">Passes additional data to be used to process the request. Of the DS_REPADD constants.</param>
		/// <returns>If the function succeeds, the return value is ERROR_SUCCESS.  If the function fails, the return value can be one of the following.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaAdd", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaAdd(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string NameContext
			, [MarshalAs(UnmanagedType.LPWStr)] string SourceDsaDn
			, [MarshalAs(UnmanagedType.LPWStr)] string TransportDn
			, [MarshalAs(UnmanagedType.LPWStr)] string SourceDsaAddress
			, [MarshalAs(UnmanagedType.LPStruct)] Schedule.SCHEDULE pSchedule
			, DWORD Options);

		/// <summary>
		/// The DsReplicaDel function removes a replication source reference from a destination naming context (NC).
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/> function.</param>
		/// <param name="NameContext">Pointer to a constant null-terminated string that specifies the distinguished name (DN) of the destination NC from which to remove the replica. The destination NC record must exist locally as either an object, instantiated or not, or a reference phantom, for example, a phantom with a GUID.</param>
		/// <param name="DsaSrc">Pointer to a constant null-terminated Unicode string that specifies the transport-specific address of the source directory system agent (DSA). This source server is identified by a string name, not by its UUID. A string name appropriate for DsaSrc is usually a DNS name that is based on a GUID, where the GUID part of the name is the GUID of the nTDSDSA object for the source server.</param>
		/// <param name="Options">Passes additional data used to process the request. This parameter can be a combination of the DS_REPLDEL constants.</param>
		/// <returns>If the function succeeds, the return value is ERROR_SUCCESS.  If the function fails, the return value is a standard Win32 API error or ERROR_INVALID_PARAMETER if a parameter is invalid.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaDel", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaDel(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string NameContext
			, [MarshalAs(UnmanagedType.LPWStr)] string DsaSrc
			, ULONG Options);

		/// <summary>
		/// The DsReplicaModify function modifies an existing replication source reference for a destination naming context.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/> function.</param>
		/// <param name="NameContext">Pointer to a constant null-terminated string that specifies the distinguished name (DN) of the destination naming context (NC).</param>
		/// <param name="pUuidSourceDsa">Pointer to the UUID of the source directory system agent (DSA). This parameter may be null if ModifyFields does not include <see cref="DS_REPMOD_UPDATE_ADDRESS"/> and SourceDsaAddress is not NULL.</param>
		/// <param name="TransportDn">Reserved for future use. Any value other than NULL results in ERROR_NOT_SUPPORTED being returned.</param>
		/// <param name="SourceDsaAddress">Pointer to a constant null-terminated Unicode string that specifies the transport-specific address of the source DSA. This parameter is ignored if pUuidSourceDsa is not NULL and ModifyFields does not include <see cref="DS_REPMOD_UPDATE_ADDRESS"/>.</param>
		/// <param name="pSchedule">Pointer to a <see cref="SCHEDULE"/> structure that contains the replication schedule data for the replication source. This parameter is optional and can be NULL if not used. This parameter is required if ModifyFields contains the <see cref="DS_REPMOD_UPDATE_ADDRESS"/> flag.</param>
		/// <param name="ReplicaFlags">Reserved for future use. Any value other than 0 results in ERROR_NOT_SUPPORTED being returned.</param>
		/// <param name="ModifyFields">Specifies what fields should be modified. At least one field must be specified in ModifyFields. This parameter can be a combination of the DS_REPMOD_UPDATE constants.</param>
		/// <param name="Options">Passes additional data used to process the request. This parameter can be a combination of the DS_REPMOD constants</param>
		/// <returns>If the function succeeds, the return value is ERROR_SUCCESS.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaModify", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaModify(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string NameContext
			, [MarshalAs(UnmanagedType.Struct)] Guid pUuidSourceDsa
			, [MarshalAs(UnmanagedType.LPWStr)] string TransportDn
			, [MarshalAs(UnmanagedType.LPWStr)] string SourceDsaAddress
			, [MarshalAs(UnmanagedType.Struct)] Schedule.SCHEDULE pSchedule
			, DWORD ReplicaFlags
			, DWORD ModifyFields
			, DWORD Options);

		/// <summary>
		/// The DsReplicaUpdateRefs function adds or removes a replication reference for a destination from a source naming context.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/> function.</param>
		/// <param name="NameContext">Pointer to a constant null-terminated string that specifies the distinguished name of the source naming context.</param>
		/// <param name="DsaDest">Pointer to a constant null-terminated string that specifies the transport-specific address of the destination directory system agent.</param>
		/// <param name="pUuidDsaDest">Pointer to a UUID value that contains the destination directory system agent.</param>
		/// <param name="Options">Contains a set of flags that provide additional data used to process the request. This can be zero or a combination of one or more of the DS_REPUPD constants.</param>
		/// <returns>If the function succeeds, ERROR_SUCCESS is returned.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaUpdateRefs", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaUpdateRefs(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string NameContext
			, [MarshalAs(UnmanagedType.LPWStr)] string DsaDest
			, [MarshalAs(UnmanagedType.Struct)] Guid pUuidDsaDest
			, ULONG Options);

		/// <summary>
		/// The DS_REPSYNCALL_ERROR enumeration is used with the <see cref="DS_REPSYNCALL_ERRINFO"/> structure to indicate where in the replication process an error occurred.
		/// </summary>
		public enum DS_REPSYNCALL_ERROR : uint
		{
			/// <summary>
			/// The server referred to by the pszSvrId member of the <see cref="DS_REPSYNCALL_ERRINFO"/> structure cannot be contacted.
			/// </summary>
			DS_REPSYNCALL_WIN32_ERROR_CONTACTING_SERVER = 0,
			/// <summary>
			/// An error occurred during replication of the server identified by the pszSvrId member of the <see cref="DS_REPSYNCALL_ERRINFO"/> structure.
			/// </summary>
			DS_REPSYNCALL_WIN32_ERROR_REPLICATING = 1,
			/// <summary>
			/// The server identified by the pszSvrId member of the <see cref="DS_REPSYNCALL_ERRINFO"/> structure cannot be contacted.
			/// </summary>
			DS_REPSYNCALL_SERVER_UNREACHABLE = 2
		}

		/// <summary>
		/// The DS_REPSYNCALL_EVENT enumeration is used with the <see cref="DS_REPSYNCALL_UPDATE"/> structure to define which event the <see cref="DS_REPSYNCALL_UPDATE"/> structure represents.
		/// </summary>
		public enum DS_REPSYNCALL_EVENT : uint
		{
			/// <summary>
			/// An error occurred. Error data is stored in the pErrInfo member of the <see cref="DS_REPSYNCALL_UPDATE"/> structure.
			/// </summary>
			DS_REPSYNCALL_EVENT_ERROR = 0,
			/// <summary>
			/// Synchronization of two servers has started. Both the pErrInfo and pSync members of the <see cref="DS_REPSYNCALL_UPDATE"/> structure are NULL.
			/// </summary>
			DS_REPSYNCALL_EVENT_SYNC_STARTED = 1,
			/// <summary>
			/// Synchronization of two servers has just finished. The servers involved in the synchronization are identified by the pSync member of the <see cref="DS_REPSYNCALL_UPDATE"/> structure. The pErrInfo member of the DS_REPSYNCALL_UPDATE structure is NULL.
			/// </summary>
			DS_REPSYNCALL_EVENT_SYNC_COMPLETED = 2,
			/// <summary>
			/// Execution of <see cref="DsReplicaSyncAll"/> is complete. Both the pErrInfo and pSync members of the <see cref="DS_REPSYNCALL_UPDATE"/> structure are NULL. The return value of the callback function is ignored.
			/// </summary>
			DS_REPSYNCALL_EVENT_FINISHED = 3
		}

		/// <summary>
		/// The DS_REPSYNCALL_SYNC structure identifies a single replication operation performed between a source, and destination, server by the <see cref="DsReplicaSyncAll"/> function.
		/// </summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPSYNCALL_SYNC
		{
			/// <summary>
			/// Pointer to a null-terminated string that specifies the DNS GUID of the source server.
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszSrcId;
			/// <summary>
			/// Pointer to a null-terminated string that specifies the DNS GUID of the destination server.
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszDstId;
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszNC;
			Guid pguidSrc;
			Guid pguidDst;
		}

		/// <summary>
		/// The DS_REPSYNCALL_ERRINFO structure is used with the <see cref="DS_REPSYNCALL_UPDATE"/> structure to contain errors generated by the <see cref="DsReplicaSyncAll"/> function during replication.
		/// </summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPSYNCALL_ERRINFO
		{
			/// <summary>
			/// Pointer to a null-terminated string that contains the DNS GUID of the server where the error occurred. Alternatively, this member can contain the distinguished name of the server if <see cref="DS_REPSYNCALL_ID_SERVERS_BY_DN"/> is specified in the ulFlags parameter of the <see cref="DsReplicaSyncAll"/> function.
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszSvrId;
			/// <summary>
			/// Contains one of the <see cref="DS_REPSYNCALL_ERROR"/> values that indicates where in the replication process the error occurred.
			/// </summary>
			DS_REPSYNCALL_ERROR error;
			/// <summary>
			/// Indicates the actual Win32 error code generated during replication between the source server referred to by pszSrcId and the destination server referred to by pszSvrId.
			/// </summary>
			DWORD dwWin32Err;
			/// <summary>
			/// Pointer to a null-terminated string that specifies the DNS GUID of the source server. Alternatively, this member can contain the distinguished name of the source server if <see cref="DS_REPSYNCALL_ID_SERVERS_BY_DN"/> is specified in the ulFlags parameter of the <see cref="DsReplicaSyncAll"/> function.
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszSrcId;
		}

		/// <summary>
		/// The DS_REPSYNCALL_UPDATE structure contains status data about the replication performed by the <see cref="DsReplicaSyncAll"/> function. The <see cref="DsReplicaSyncAll"/> function passes this structure to a callback function in its pFnCallBack parameter. For more information about the callback function, see <see cref="SyncUpdateProc"/>.
		/// </summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPSYNCALL_UPDATE
		{
			/// <summary>
			/// Contains a <see cref="DS_REPSYNCALL_EVENT"/> value that describes the event which the <see cref="DS_REPSYNCALL_UPDATE"/> structure represents.
			/// </summary>
			[MarshalAs(UnmanagedType.Struct)]
			DS_REPSYNCALL_EVENT replevent;
			/// <summary>
			/// Pointer to a <see cref="DS_REPSYNCALL_ERRINFO"/> structure that contains error data about the replication performed by the <see cref="DsReplicaSyncAll"/> function.
			/// </summary>
			[MarshalAs(UnmanagedType.Struct)]
			DS_REPSYNCALL_ERRINFO pErrInfo;
			/// <summary>
			/// Pointer to a <see cref="DS_REPSYNCALL_SYNC"/> structure that identifies the source and destination servers that have either initiated or finished synchronization.
			/// </summary>
			[MarshalAs(UnmanagedType.Struct)]
			DS_REPSYNCALL_SYNC pSync;
		}

		/// <summary>
		/// This option has no effect.
		/// </summary>
		public const uint DS_REPSYNCALL_NO_OPTIONS = 0x00000000;
		/// <summary>
		/// Ordinarily, if a server cannot be contacted, DsReplicaSyncAll tries to
		/// route around it and replicate from as many servers as possible.  Enabling
		/// this option will cause DsReplicaSyncAll to generate a fatal error if any
		/// server cannot be contacted, or if any server is unreachable (due to a
		/// disconnected or broken topology.)
		/// </summary>
		public const uint DS_REPSYNCALL_ABORT_IF_SERVER_UNAVAILABLE = 0x00000001;
		/// <summary>
		/// This option disables transitive replication; syncs will only be performed
		/// with adjacent servers and no DsBind calls will be made.
		/// </summary>
		public const uint DS_REPSYNCALL_SYNC_ADJACENT_SERVERS_ONLY = 0x00000002;
		/// <summary>
		/// Ordinarily, when DsReplicaSyncAll encounters a non-fatal error, it returns
		/// the GUID DNS of the relevant server(s).  Enabling this option causes
		/// DsReplicaSyncAll to return the servers' DNs instead.
		/// </summary>
		public const uint DS_REPSYNCALL_ID_SERVERS_BY_DN = 0x00000004;
		/// <summary>
		/// This option disables all syncing.  The topology will still be analyzed and
		/// unavailable / unreachable servers will still be identified.
		/// </summary>
		public const uint DS_REPSYNCALL_DO_NOT_SYNC = 0x00000008;
		/// <summary>
		/// Ordinarily, DsReplicaSyncAll attempts to bind to all servers before
		/// generating the topology.  If a server cannot be contacted, DsReplicaSyncAll
		/// excludes that server from the topology and tries to route around it.  If
		/// this option is enabled, checking will be bypassed and DsReplicaSyncAll will
		/// assume all servers are responding.  This will speed operation of
		/// DsReplicaSyncAll, but if some servers are not responding, some transitive
		/// replications may be blocked.
		/// </summary>
		public const uint DS_REPSYNCALL_SKIP_INITIAL_CHECK = 0x00000010;
		/// <summary>
		/// Push mode. Push changes from the home server out to all partners using
		/// transitive replication.  This reverses the direction of replication, and
		/// the order of execution of the replication sets from the usual "pulling"
		/// mode of execution.
		/// </summary>
		public const uint DS_REPSYNCALL_PUSH_CHANGES_OUTWARD = 0x00000020;
		/// <summary>
		/// Cross site boundaries.  By default, the only servers that are considered are
		/// those in the same site as the home system.  With this option, all servers in
		/// the enterprise, across all sites, are eligible.  They must be connected by
		/// a synchronous (RPC) transport, however.
		/// </summary>
		public const uint DS_REPSYNCALL_CROSS_SITE_BOUNDARIES = 0x00000040;

		/// <summary>
		/// The DsReplicaSyncAll function synchronizes a server with all other servers, using transitive replication, as necessary. By default, DsReplicaSyncAll synchronizes the server with all other servers in its site; however, you can also use it to synchronize across site boundaries.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DsBind"/> or <see cref="DsBindWithCred"/> function.</param>
		/// <param name="pszNameContext">Pointer to a null-terminated string that specifies the distinguished name of the naming context to synchronize. The pszNameContext parameter is optional; if its value is NULL, the configuration naming context is replicated.</param>
		/// <param name="ulFlags">Passes additional data used to process the request. This parameter can be any of the DS_REPSYNCALL constants.</param>
		/// <param name="pFnCallBack"></param>
		/// <param name="pCallbackData">Pointer to application-defined data passed as the first argument of the <see cref="SyncUpdateProc"/> callback function pointed to by the pFnCallBack parameter.</param>
		/// <param name="pErrors">A NULL-terminated array of pointers to <see cref="DS_REPSYNCALL_ERRINFO"/> structures that contain errors that occurred during synchronization. The memory used to hold both the array of pointers and the ERRINFO data is allocated as a single block of memory and should be freed when no longer required by a single call to LocalFree with the pointer value returned in pErrors used as the argument.</param>
		/// <returns>If the function succeeds, the return value is ERROR_SUCCESS.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaSyncAll", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaSyncAll(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string pszNameContext
			, ULONG ulFlags
			, bool pFnCallBack
			, Delegate pCallbackData
			, [MarshalAs(UnmanagedType.LPStruct)] out DS_REPSYNCALL_ERRINFO pErrors);
		#endregion

		#region Manage AD Site/Topology
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsRemoveDsServer", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsRemoveDsServer(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string ServerDN
			, [MarshalAs(UnmanagedType.LPWStr)] string DomainDN
			, out bool fLastDcInDomain
			, bool fCommit);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsRemoveDsDomain", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsRemoveDsDomain(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.LPWStr)] string DomainDn);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsListSites", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsListSites(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.Struct)] out DS_NAME_RESULT ppSites);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsListServersInSite", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsListServersInSite(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.LPWStr)] string site
			, [MarshalAs(UnmanagedType.Struct)] out DS_NAME_RESULT ppServers);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsListDomainsInSite", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsListDomainsInSite(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.LPWStr)] string site
			, [MarshalAs(UnmanagedType.Struct)] out DS_NAME_RESULT ppServers);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsListServersForDomainInSite", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsListServersForDomainInSite(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.LPWStr)] string domain
			, [MarshalAs(UnmanagedType.LPWStr)] string site
			, [MarshalAs(UnmanagedType.Struct)] out DS_NAME_RESULT ppServers);

		public const uint DS_LIST_DSA_OBJECT_FOR_SERVER = 0;
		public const uint DS_LIST_DNS_HOST_NAME_FOR_SERVER = 1;
		public const uint DS_LIST_ACCOUNT_OBJECT_FOR_SERVER = 2;

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsListInfoForServer", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsListInfoForServer(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.LPWStr)] string server
			, [MarshalAs(UnmanagedType.Struct)] out DS_NAME_RESULT ppInfo);

		// Define indices for DsListRoles return data.  Check status for
		// each field as a given value may not be present.
		public const uint DS_ROLE_SCHEMA_OWNER = 0;
		public const uint DS_ROLE_DOMAIN_OWNER = 1;
		public const uint DS_ROLE_PDC_OWNER = 2;
		public const uint DS_ROLE_RID_OWNER = 3;
		public const uint DS_ROLE_INFRASTRUCTURE_OWNER = 4;

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsListRoles", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsListRoles(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.Struct)] out DS_NAME_RESULT ppRoles);

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_SITE_COST_INFO
		{
			DWORD errorCode;
			DWORD cost;
		}

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsQuerySitesByCost", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsQuerySitesByCost(
			DsHandle hDs
			, [MarshalAs(UnmanagedType.LPWStr)] string pwszFromSite
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgwszToSites
			, DWORD cToSites
			, DWORD dwFlags
			, [MarshalAs(UnmanagedType.Struct)] DS_SITE_COST_INFO prgSiteInfo);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsQuerySitesFree", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern void DsQuerySitesFree(DS_SITE_COST_INFO rgSiteInfo);
		#endregion

		#region Schema Stuff
		public const uint DS_SCHEMA_GUID_NOT_FOUND = 0;
		public const uint DS_SCHEMA_GUID_ATTR = 1;
		public const uint DS_SCHEMA_GUID_ATTR_SET = 2;
		public const uint DS_SCHEMA_GUID_CLASS = 3;
		public const uint DS_SCHEMA_GUID_CONTROL_RIGHT = 4;

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_SCHEMA_GUID_MAP
		{
			[MarshalAs(UnmanagedType.LPStruct)]
			Guid guid;
			DWORD guidType;
			[MarshalAs(UnmanagedType.LPWStr)]
			string pName;
		}

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsMapSchemaGuids", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsMapSchemaGuids(
			DsHandle hDS
			, DWORD cGuids
			, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 1)] Guid[] pszObject
			, DS_SCHEMA_GUID_MAP ppGuidMap);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsFreeSchemaGuidMap", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsFreeSchemaGuidMap(DS_SCHEMA_GUID_MAP pGuidMap);
		#endregion

		#region Get Domain Controller Infos
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_DOMAIN_CONTROLLER_INFO_1
		{
			public string NetbiosName;
			public string DnsHostName;
			public string SiteName;
			public string ComputerObjectName;
			public string ServerObjectName;
			public bool fIsPdc;
			public bool fDsEnabled;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_DOMAIN_CONTROLLER_INFO_2
		{
			public string NetbiosName;
			public string DnsHostName;
			public string SiteName;
			public string SiteObjectName;
			public string ComputerObjectName;
			public string ServerObjectName;
			public string NtdsDsaObjectName;
			public bool fIsPdc;
			public bool fDsEnabled;
			public bool fIsGc;
			public Guid SiteObjectGuid;
			public Guid ComputerObjectGuid;
			public Guid ServerObjectGuid;
			public Guid NtdsDsaObjectGuid;
		}

		/// <summary>
		/// The DsGetDomainControllerInfo function retrieves data about the domain controllers in a domain.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the DSBind or DSBindWithCred function.</param>
		/// <param name="DomainName">Pointer to a null-terminated string that specifies the domain name.</param>
		/// <param name="InfoLevel">Contains a value that indicates the version of the <see cref="DS_DOMAIN_CONTROLLER_INFO"/> structure to return. This can be one of the following values.</param>
		/// <param name="pcOut">Pointer to a DWORD variable that receives the number of items returned in ppInfo array.</param>
		/// <param name="ppInfo">Pointer to a pointer variable that receives an array of <see cref="DS_DOMAIN_CONTROLLER_INFO_*"/> structures. The type of structures in this array is defined by the InfoLevel parameter. The caller must free this array, when it is no longer required, by using the DsFreeDomainControllerInfo function.</param>
		/// <returns>If the function returns domain controller data, the return value is ERROR_SUCCESS. If the caller does not have the privileges to access the server objects, the return value is ERROR_SUCCESS, but the <see cref="DS_DOMAIN_CONTROLLER_INFO"/> structures could be empty.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsGetDomainControllerInfo", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsGetDomainControllerInfo(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string DomainName
			, DWORD InfoLevel
			, out DWORD pcOut
			, out IntPtr ppInfo);

		/// <summary>
		/// The DsFreeDomainControllerInfo function frees memory that is allocated by DsGetDomainControllerInfo for data about the domain controllers in a domain.
		/// </summary>
		/// <param name="infoLevel">Indicates what version of the <see cref="DS_DOMAIN_CONTROLLER_INFO"/> structure should be freed. </param>
		/// <param name="cInfo">Indicates the number of items in pInfo.</param>
		/// <param name="pInfo">Pointer to an array of <see cref="DS_DOMAIN_CONTROLLER_INFO"/> structures to be freed.</param>
		/// <returns>This function does not return a value. </returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsFreeDomainControllerInfo", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		internal static extern void DsFreeDomainControllerInfo(
			DWORD infoLevel
			, DWORD cInfo
			, IntPtr pInfo);
		#endregion

		#region KCC management
		/// <summary>
		/// Which task should be run?
		/// </summary>
		public enum DS_KCC_TASKID
		{
			DS_KCC_TASKID_UPDATE_TOPOLOGY = 0
		}

		/// <summary>
		/// Don't wait for completion of the task; queue it and return.
		/// </summary>
		public const uint DS_KCC_FLAG_ASYNC_OP = (1 << 0);

		/// <summary>
		/// Don't enqueue the task if another queued task will run soon.
		/// </summary>
		public const uint DS_KCC_FLAG_DAMPED = (1 << 1);

		/// <summary>
		/// The DsReplicaConsistencyCheck function invokes the Knowledge Consistency Checker (KCC) to verify the replication topology. The KCC dynamically adjusts the data replication topology of your network when domain controllers are added to or removed from the network, when a domain controller is unavailable, or when the data replication schedules are changed.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the <see cref="DSBind"/>, <see cref="DSBindWithCred"/>, or <see cref="DsBindWithSpn"/> function.</param>
		/// <param name="TaskID">Identifies the task that the KCC should execute. DS_KCC_TASKID_UPDATE_TOPOLOGY is the only currently supported value.</param>
		/// <param name="dwFlags">Contains a set of flags that modify the function behavior. This can be zero or a combination of one or more of the DS_KCC_FLAG_* values.</param>
		/// <returns>If the function performs its operation successfully, the return value is ERROR_SUCCESS.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaConsistencyCheck", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaConsistencyCheck(
			HANDLE hDS
			, DS_KCC_TASKID TaskID
			, DWORD dwFlags);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaVerifyObjects", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaVerifyObjects(
			DsHandle hDS
			, [MarshalAs(UnmanagedType.LPWStr)] string nameContext
			, [MarshalAs(UnmanagedType.LPStruct)] Guid pUuidDsaSrc
			, ulong ulOptions
			);
		#endregion

		#region Replication Management
		/// <summary>
		/// Do not delete objects on DsReplicaVerifyObjects call
		/// </summary>
		public const uint DS_EXIST_ADVISORY_MODE = 0x1;

		/// <summary>
		/// The DS_REPL_INFO_TYPE enumeration is used with the <see cref="DsReplicaGetInfo"/> and <see cref="DsReplicaGetInfo2"/> functions to specify the type of replication data to retrieve.
		/// </summary>
		public enum DS_REPL_INFO_TYPE : uint
		{
			/// <summary>
			/// Requests replication state data for naming context and source server pairs. Returns a pointer to a <see cref="DS_REPL_NEIGHBORS"/> structure.
			/// </summary>
			DS_REPL_INFO_NEIGHBORS = 0,
			/// <summary>
			/// Requests replication state data with respect to all replicas of a given naming context. Returns a pointer to a <see cref="DS_REPL_CURSORS"/> structure.
			/// </summary>
			DS_REPL_INFO_CURSORS_FOR_NC = 1,
			/// <summary>
			/// Requests replication state data for the attributes for the given object. Returns a pointer to a <see cref="DS_REPL_OBJ_META_DATA"/> structure.
			/// </summary>
			DS_REPL_INFO_METADATA_FOR_OBJ = 2,
			/// <summary>
			/// Requests replication state data with respect to connection failures between inbound replication partners. Returns a pointer to a <see cref="DS_REPL_KCC_DSA_FAILURES"/> structure.
			/// </summary>
			DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES = 3,
			/// <summary>
			/// Requests replication state data with respect to link failures between inbound replication partners. Returns a pointer to a <see cref="DS_REPL_KCC_DSA_FAILURES"/> structure.
			/// </summary>
			DS_REPL_INFO_KCC_DSA_LINK_FAILURES = 4,
			/// <summary>
			/// Requests the replication tasks currently executing or queued to execute. Returns a pointer to a <see cref="DS_REPL_PENDING_OPS"/> structure.
			/// </summary>
			DS_REPL_INFO_PENDING_OPS = 5,

			////////////////////////////////////////////////////////////////////////////
			//
			//  The following info types are not supported by Windows 2000.  Calling
			//  DsReplicaGetInfo() with one of the types on a Windows 2000 client or
			//  where hDS is bound to a Windows 2000 DC will fail with
			//  ERROR_NOT_SUPPORTED.
			//

			/// <summary>
			/// Requests replication state data for a specific attribute for the given object. Returns a pointer to a <see cref="DS_REPL_ATTR_VALUE_META_DATA"/> structure.
			/// </summary>
			DS_REPL_INFO_METADATA_FOR_ATTR_VALUE = 6,
			/// <summary>
			/// Requests replication state data with respect to all replicas of a given naming context. Returns a pointer to a <see cref="DS_REPL_CURSORS_2"/> structure.
			/// </summary>
			DS_REPL_INFO_CURSORS_2_FOR_NC = 7,
			/// <summary>
			/// Requests replication state data with respect to all replicas of a given naming context. Returns a pointer to a <see cref="DS_REPL_CURSORS_3"/> structure.
			/// </summary>
			DS_REPL_INFO_CURSORS_3_FOR_NC = 8,
			/// <summary>
			/// Requests replication state data for the attributes for the given object. Returns a pointer to a <see cref="DS_REPL_OBJ_META_DATA_2"/> structure.
			/// </summary>
			DS_REPL_INFO_METADATA_2_FOR_OBJ = 9,
			/// <summary>
			/// Requests replication state data for a specific attribute for the given object. Returns a pointer to a <see cref="DS_REPL_ATTR_VALUE_META_DATA_2"/> structure.
			/// </summary>
			DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE = 10,
		}

		/// <summary>
		/// Bit values for flags argument to DsReplicaGetInfo2
		/// </summary>
		public const uint DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS = 0x00000001;

		/// <summary>
		/// Bit values for the dwReplicaFlags field of the DS_REPL_NEIGHBOR structure.
		/// Also used for the ulReplicaFlags argument to DsReplicaModify
		/// </summary>
		public const uint DS_REPL_NBR_WRITEABLE = (0x00000010);
		public const uint DS_REPL_NBR_SYNC_ON_STARTUP = (0x00000020);
		public const uint DS_REPL_NBR_DO_SCHEDULED_SYNCS = (0x00000040);
		public const uint DS_REPL_NBR_USE_ASYNC_INTERSITE_TRANSPORT = (0x00000080);
		public const uint DS_REPL_NBR_TWO_WAY_SYNC = (0x00000200);
		public const uint DS_REPL_NBR_NONGC_RO_REPLICA = (0x00000400);
		public const uint DS_REPL_NBR_RETURN_OBJECT_PARENTS = (0x00000800);
		public const uint DS_REPL_NBR_SELECT_SECRETS = (0x00001000);
		public const uint DS_REPL_NBR_FULL_SYNC_IN_PROGRESS = (0x00010000);
		public const uint DS_REPL_NBR_FULL_SYNC_NEXT_PACKET = (0x00020000);
		public const uint DS_REPL_NBR_GCSPN = (0x00100000);
		public const uint DS_REPL_NBR_NEVER_SYNCED = (0x00200000);
		public const uint DS_REPL_NBR_PREEMPTED = (0x01000000);
		public const uint DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS = (0x04000000);
		public const uint DS_REPL_NBR_DISABLE_SCHEDULED_SYNC = (0x08000000);
		public const uint DS_REPL_NBR_COMPRESS_CHANGES = (0x10000000);
		public const uint DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS = (0x20000000);
		public const uint DS_REPL_NBR_PARTIAL_ATTRIBUTE_SET = (0x40000000);
		/// <summary>
		/// This is the mask of replica flags that may be changed on the DsReplicaModify
		/// call using the ulReplicaFlags parameter. The other flags are protected
		/// system flags.  The previous values of the system flags must be read in
		/// advance and merged into the ulReplicaFlags parameter unchanged.
		/// </summary>
		public const uint DS_REPL_NBR_MODIFIABLE_MASK = (DS_REPL_NBR_SYNC_ON_STARTUP | DS_REPL_NBR_DO_SCHEDULED_SYNCS | DS_REPL_NBR_TWO_WAY_SYNC | DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS | DS_REPL_NBR_DISABLE_SCHEDULED_SYNC | DS_REPL_NBR_COMPRESS_CHANGES | DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS);

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_NEIGHBOR
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszNamingContext;
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszSourceDsaDN;
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszSourceDsaAddress;
			[MarshalAs(UnmanagedType.LPWStr)]
			string pszAsyncIntersiteTransportDN;
			DWORD dwReplicaFlags;
			DWORD dwReserved;         // alignment
			UUID uuidNamingContextObjGuid;
			UUID uuidSourceDsaObjGuid;
			UUID uuidSourceDsaInvocationID;
			UUID uuidAsyncIntersiteTransportObjGuid;
			USN usnLastObjChangeSynced;
			USN usnAttributeFilter;
			FILETIME ftimeLastSyncSuccess;
			FILETIME ftimeLastSyncAttempt;
			DWORD dwLastSyncResult;
			DWORD cNumConsecutiveSyncFailures;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_NEIGHBORW_BLOB
		{
			DWORD oszNamingContext;
			DWORD oszSourceDsaDN;
			DWORD oszSourceDsaAddress;
			DWORD oszAsyncIntersiteTransportDN;
			DWORD dwReplicaFlags;
			DWORD dwReserved;

			UUID uuidNamingContextObjGuid;
			UUID uuidSourceDsaObjGuid;
			UUID uuidSourceDsaInvocationID;
			UUID uuidAsyncIntersiteTransportObjGuid;

			USN usnLastObjChangeSynced;
			USN usnAttributeFilter;

			FILETIME ftimeLastSyncSuccess;
			FILETIME ftimeLastSyncAttempt;

			DWORD dwLastSyncResult;
			DWORD cNumConsecutiveSyncFailures;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_NEIGHBORSW
		{
			DWORD cNumNeighbors;
			DWORD dwReserved;
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_NEIGHBOR[] rgNeighbor;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSOR
		{
			UUID uuidSourceDsaInvocationID;
			USN usnAttributeFilter;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSOR_2
		{
			UUID uuidSourceDsaInvocationID;
			USN usnAttributeFilter;
			FILETIME ftimeLastSyncSuccess;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSOR_3
		{
			UUID uuidSourceDsaInvocationID;
			USN usnAttributeFilter;
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszSourceDsaDN;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSOR_BLOB
		{
			UUID uuidSourceDsaInvocationID;
			USN usnAttributeFilter;
			[MarshalAs(UnmanagedType.LPWStr)]
			DWORD oszSourceDsaDN;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSORS
		{
			DWORD cNumCursors;
			DWORD dwEnumerationContext;
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_CURSOR[] rgCursor;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSORS_2
		{
			DWORD cNumCursors;
			DWORD dwEnumerationContext;
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_CURSOR_2[] rgCursor;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_CURSORS_3
		{
			DWORD cNumCursors;
			DWORD dwEnumerationContext;
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_CURSOR_3[] rgCursor;
		}


		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_ATTR_META_DATA
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszAttributeName;
			DWORD dwVersion;
			FILETIME ftimeLastOriginatingChange;
			UUID uuidLastOriginatingDsaInvocationID;
			USN usnOriginatingChange;   // in the originating DSA's USN space
			USN usnLocalChange;         // in the local DSA's USN space
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_ATTR_META_DATA_2
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszAttributeName;
			DWORD dwVersion;
			FILETIME ftimeLastOriginatingChange;
			UUID uuidLastOriginatingDsaInvocationID;
			USN usnOriginatingChange;   // in the originating DSA's USN space
			USN usnLocalChange;         // in the local DSA's USN space
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszLastOriginatingDsaDN;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_ATTR_META_DATA_BLOB
		{
			DWORD oszAttributeName;
			DWORD dwVersion;
			FILETIME ftimeLastOriginatingChange;
			UUID uuidLastOriginatingDsaInvocationID;
			USN usnOriginatingChange;   // in the originating DSA's USN space
			USN usnLocalChange;         // in the local DSA's USN space
			DWORD oszLastOriginatingDsaDN;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_OBJ_META_DATA
		{
			DWORD cNumEntries;
			DWORD dwReserved;             // alignment
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_ATTR_META_DATA[] rgMetaData;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_OBJ_META_DATA_2
		{
			DWORD cNumEntries;
			DWORD dwReserved;             // alignment
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_ATTR_META_DATA_2[] rgMetaData;
		}
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_KCC_DSA_FAILURE
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszDsaDN;
			UUID uuidDsaObjGuid;
			FILETIME ftimeFirstFailure;
			DWORD cNumFailures;
			DWORD dwLastResult;   // Win32 error code
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_KCC_DSA_FAILUREW_BLOB
		{
			DWORD oszDsaDN;
			UUID uuidDsaObjGuid;
			FILETIME ftimeFirstFailure;
			DWORD cNumFailures;
			DWORD dwLastResult;   // Win32 error code
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_KCC_DSA_FAILURES
		{
			DWORD cNumEntries;
			DWORD dwReserved;             // alignment
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_KCC_DSA_FAILURE rgDsaFailure;
		}

		public enum DS_REPL_OP_TYPE
		{
			DS_REPL_OP_TYPE_SYNC = 0,
			DS_REPL_OP_TYPE_ADD,
			DS_REPL_OP_TYPE_DELETE,
			DS_REPL_OP_TYPE_MODIFY,
			DS_REPL_OP_TYPE_UPDATE_REFS
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_OPW
		{
			FILETIME ftimeEnqueued;  // time at which the operation was enqueued
			ULONG ulSerialNumber; // ID of this sync; unique per machine per boot
			ULONG ulPriority;     // > priority, > urgency
			DS_REPL_OP_TYPE OpType;

			ULONG ulOptions;      // Zero or more bits specific to OpType; e.g.,
			//  DS_REPADD_* for DS_REPL_OP_TYPE_ADD,
			//  DS_REPSYNC_* for DS_REPL_OP_TYPE_SYNC, etc.
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszNamingContext;
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszDsaDN;
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszDsaAddress;

			UUID uuidNamingContextObjGuid;
			UUID uuidDsaObjGuid;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_OPW_BLOB
		{
			FILETIME ftimeEnqueued;  // time at which the operation was enqueued
			ULONG ulSerialNumber; // ID of this sync; unique per machine per boot
			ULONG ulPriority;     // > priority, > urgency
			DS_REPL_OP_TYPE OpType;

			ULONG ulOptions;      // Zero or more bits specific to OpType; e.g.,
			//  DS_REPADD_* for DS_REPL_OP_TYPE_ADD,
			//  DS_REPSYNC_* for DS_REPL_OP_TYPE_SYNC, etc.
			DWORD oszNamingContext;
			DWORD oszDsaDN;
			DWORD oszDsaAddress;

			UUID uuidNamingContextObjGuid;
			UUID uuidDsaObjGuid;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_PENDING_OPSW
		{
			FILETIME ftimeCurrentOpStarted;
			DWORD cNumPendingOps;
			DS_REPL_OPW[] rgPendingOp;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_VALUE_META_DATA
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszAttributeName;
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszObjectDn;
			DWORD cbData;
			[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
			byte[] pbData;
			FILETIME ftimeDeleted;
			FILETIME ftimeCreated;
			DWORD dwVersion;
			FILETIME ftimeLastOriginatingChange;
			UUID uuidLastOriginatingDsaInvocationID;
			USN usnOriginatingChange;   // in the originating DSA's USN space
			USN usnLocalChange;         // in the local DSA's USN space
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_VALUE_META_DATA_2
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszAttributeName;
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszObjectDn;
			DWORD cbData;
			[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
			byte[] pbData;
			FILETIME ftimeDeleted;
			FILETIME ftimeCreated;
			DWORD dwVersion;
			FILETIME ftimeLastOriginatingChange;
			UUID uuidLastOriginatingDsaInvocationID;
			USN usnOriginatingChange;   // in the originating DSA's USN space
			USN usnLocalChange;         // in the local DSA's USN space
			[MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder pszLastOriginatingDsaDN;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_VALUE_META_DATA_BLOB
		{
			DWORD oszAttributeName;
			DWORD oszObjectDn;
			DWORD cbData;
			DWORD obData;
			FILETIME ftimeDeleted;
			FILETIME ftimeCreated;
			DWORD dwVersion;
			FILETIME ftimeLastOriginatingChange;
			UUID uuidLastOriginatingDsaInvocationID;
			USN usnOriginatingChange;   // in the originating DSA's USN space
			USN usnLocalChange;         // in the local DSA's USN space
			DWORD oszLastOriginatingDsaDN;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_ATTR_VALUE_META_DATA
		{
			DWORD cNumEntries;
			DWORD dwEnumerationContext;
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_VALUE_META_DATA[] rgMetaData;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_ATTR_VALUE_META_DATA_2
		{
			DWORD cNumEntries;
			DWORD dwEnumerationContext;
			[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)]
			DS_REPL_VALUE_META_DATA_2[] rgMetaData;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_QUEUE_STATISTICS
		{
			FILETIME ftimeCurrentOpStarted;
			DWORD cNumPendingOps;
			FILETIME ftimeOldestSync;
			FILETIME ftimeOldestAdd;
			FILETIME ftimeOldestMod;
			FILETIME ftimeOldestDel;
			FILETIME ftimeOldestUpdRefs;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class DS_REPL_QUEUE_STATISTICS_BLOB
		{
			FILETIME ftimeCurrentOpStarted;
			DWORD cNumPendingOps;
			FILETIME ftimeOldestSync;
			FILETIME ftimeOldestAdd;
			FILETIME ftimeOldestMod;
			FILETIME ftimeOldestDel;
			FILETIME ftimeOldestUpdRefs;
		}

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaGetInfo", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaGetInfo(
			DsHandle hDS
			, DS_REPL_INFO_TYPE InfoType
			, [MarshalAs(UnmanagedType.LPWStr)] string pszObject
			, [MarshalAs(UnmanagedType.LPStruct)] Guid puuidForSourceDsaObjGuid
			, out IntPtr ppInfo);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaGetInfo2", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsReplicaGetInfo2(
			DsHandle hDS
			, DS_REPL_INFO_TYPE InfoType
			, [MarshalAs(UnmanagedType.LPWStr)] string pszObject
			, [MarshalAs(UnmanagedType.LPStruct)] Guid puuidForSourceDsaObjGuid
			, [MarshalAs(UnmanagedType.LPWStr)] string pszAttributeName
			, [MarshalAs(UnmanagedType.LPWStr)] string pszValue
			, DWORD dwFlags
			, DWORD dwEnumerationContext
			, out IntPtr ppInfo);

		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsReplicaFreeInfo", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern void DsReplicaFreeInfo(
			DS_REPL_INFO_TYPE InfoType
			, IntPtr pInfo);
		#endregion

		#region Manage Sid History
		/// <summary>
		/// The DsAddSidHistory function retrieves the primary account security identifier (SID) of a security principal from one domain and adds it to the sIDHistory attribute of a security principal in another domain in a different forest. When the source domain is in Windows 2000 native mode, this function also retrieves the sIDHistory values of the source principal and adds them to the destination principal sIDHistory.
		/// <para>The DsAddSidHistory function performs a security-sensitive function by adding the primary account SID of an existing security principal to the sIDHistory of a principal in a domain in a different forest, effectively granting to the latter access to all resources accessible to the former. For more information about the use and security implications of this function, see Using DsAddSidHistory.</para>
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the DSBind or DSBindWithCred function.</param>
		/// <param name="Flags">Reserved for future use. Set to NULL.</param>
		/// <param name="SrcDomain">Pointer to a null-terminated string that specifies the name of the domain to query for the SID of SrcPrincipal.
		/// <para>If the source domain runs on Windows Server 2003 operating systems, SrcDomain can be either a domain name system (DNS) name, for example, fabrikam.com, or a flat NetBIOS, for example, Fabrikam, name. DNS names should be used when possible.</para>
		/// <para>If the source domain is Windows 2000, SrcDomain must be a DNS name.</para>
		/// <para>If the source domain is Windows NT 4.0, SrcDomain must be a NetBIOS name.</para>
		///</param>
		/// <param name="SrcPrincipal">Pointer to a null-terminated string that specifies the name of a security principal, user or group, in the source domain. This name is a domain-relative Security Account Manager (SAM) name, for example: evacorets.</param>
		/// <param name="SrcDomainController">Pointer to a null-terminated string that specifies the name of the primary domain controller (PDC) (PDC for Windows NT 4.0, PDC Emulator for Windows 2000, or Windows Server 2003) in the source domain to use for secure retrieval of the source principal SID and audit generation. If this parameter is NULL, DSBindWithCred will select the primary domain controller.
		/// <para>If the source domain controller runs on Windows Server 2003 operating systems, SrcDomainController can be either a DNS name or a flat NetBIOS name. DNS names should be used when possible.</para>
		/// <para>If the source domain is Windows 2000, SrcDomainController must be a DNS name.</para>
		/// <para>If the source domain is Windows NT 4.0, SrcDomainController must be a NetBIOS name.</para>
		/// </param>
		/// <param name="SrcDomainCreds">Contains an identity handle that represents the identity and credentials of a user with administrative rights in the source domain. To obtain this handle, call DsMakePasswordCredentials. This user must be a member of either the Administrators or the Domain Administrators group. If this call is made from a remote computer to the destination DC, then both the remote computer and the destination DC must support 128-bit encryption to privacy-protect the credentials. If 128-bit encryption is unavailable and SrcDomainCreds are provided, then the call must be made on the destination DC.</param>
		/// <param name="DstDomain">Pointer to a null-terminated string that specifies the name of the destination domain in which DstPrincipal resides. This name can either be a DNS name, for example, fabrikam.com, or a NetBIOS name, for example, Fabrikam. The destination domain must run Windows 2000 native mode.</param>
		/// <param name="DstPrincipal">Pointer to a null-terminated string that specifies the name of a security principal, user or group, in the destination domain. This domain-relative SAM name identifies the principal whose sIDHistory attribute is updated with the SID of the SrcPrincipal.</param>
		/// <returns>Returns a Win32 error codes including the following.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsAddSidHistory", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsAddSidHistory(
			DsHandle hDS
			, DWORD Flags
			, [MarshalAs(UnmanagedType.LPWStr)] string SrcDomain
			, [MarshalAs(UnmanagedType.LPWStr)] string SrcPrincipal
			, [MarshalAs(UnmanagedType.LPWStr)] string SrcDomainController
			, [MarshalAs(UnmanagedType.LPWStr)] RPC_AUTH_IDENTITY_HANDLE SrcDomainCreds
			, [MarshalAs(UnmanagedType.LPStr)] string DstDomain
			, [MarshalAs(UnmanagedType.LPStr)] string DstPrincipal);

		/// <summary>
		/// The DsInheritSecurityIdentity function appends the objectSid and sidHistory attributes of SrcPrincipal to the sidHistory of DstPrincipal and then deletes SrcPrincipal, all in a single transaction. To ensure that this operation is atomic, SrcPrincipal and DstPrincipal must be in the same domain and hDS must be bound to a domain controller that the correct permissions within that domain.
		/// </summary>
		/// <param name="hDS">Contains a directory service handle obtained from either the DSBind or DSBindWithCred function.</param>
		/// <param name="Flags">Reserved for future use. Must be zero.</param>
		/// <param name="SrcPrincipal">Pointer to a null-terminated string that specifies the name of a security principal (user or group) in the source domain. This name is a domain-relative SAM name.</param>
		/// <param name="DstPrincipal">Pointer to a null-terminated string that specifies the name of a security principal (user or group) in the destination domain. This domain-relative SAM name identifies the principal whose sidHistory attribute will be updated with the SID of SrcPrincipal.</param>
		/// <returns>Returns a system or RPC error code including the following.</returns>
		[DllImport("Ntdsapi.dll", CharSet = CharSet.Auto, EntryPoint = "DsInheritSecurityIdentity", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		static public extern DWORD DsInheritSecurityIdentity(
			DsHandle hDS
			, DWORD Flags
			, [MarshalAs(UnmanagedType.LPWStr)] string SrcPrincipal
			, [MarshalAs(UnmanagedType.LPWStr)] string DstPrincipal);
		#endregion


		#endregion
	}
}